From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=104.47.34.124; helo=nam01-by2-obe.outbound.protection.outlook.com; envelope-from=christopher.co@microsoft.com; receiver=edk2-devel@lists.01.org Received: from NAM01-BY2-obe.outbound.protection.outlook.com (mail-by2nam01on0124.outbound.protection.outlook.com [104.47.34.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 082DB202E5446 for ; Wed, 18 Jul 2018 21:11:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=CuVuKBokPlNlPxEyeco7jEfxLsNG9xuHKcSaDa5U0ks=; b=Vpsa4hpoV5qBIC/AGi0XPY/+f2B5GwLMONoNF4a9Q4RHGgCCR3TcObu2xdw9vhPVexJL4Ib7oU8dfUiZOOozIjDx7ht31w8dQrelzkD5U4U4ijuWzXpoxhKYQNynVk1yfQaD/cq1T/BCTiH76MPE/MF13djLpUey8Q4N0bSi4Cc= Received: from DM5PR2101MB1128.namprd21.prod.outlook.com (52.132.133.20) by DM5PR2101MB0983.namprd21.prod.outlook.com (52.132.133.29) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.995.0; Thu, 19 Jul 2018 04:11:18 +0000 Received: from DM5PR2101MB1128.namprd21.prod.outlook.com ([fe80::b4d3:dabb:9372:9740]) by DM5PR2101MB1128.namprd21.prod.outlook.com ([fe80::b4d3:dabb:9372:9740%2]) with mapi id 15.20.0995.008; Thu, 19 Jul 2018 04:11:18 +0000 From: Chris Co To: "edk2-devel@lists.01.org" CC: Ard Biesheuvel , Leif Lindholm , Michael D Kinney Thread-Topic: [PATCH edk2-platforms 1/7] Silicon/NXP: Add support for iMX SDHC Thread-Index: AQHUHxaKKE2XqFnFn0SByyM3CCUcDA== Date: Thu, 19 Jul 2018 04:11:18 +0000 Message-ID: <20180719041103.9072-2-christopher.co@microsoft.com> References: <20180719041103.9072-1-christopher.co@microsoft.com> In-Reply-To: <20180719041103.9072-1-christopher.co@microsoft.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: BN6PR11CA0037.namprd11.prod.outlook.com (2603:10b6:404:4b::23) To DM5PR2101MB1128.namprd21.prod.outlook.com (2603:10b6:4:a8::20) x-ms-exchange-messagesentrepresentingtype: 1 x-originating-ip: [2001:4898:80e8:1:d144:e4c:c05:68bd] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1; DM5PR2101MB0983; 6:NiCursKr2n6uS1/2y41OR4+dNKKf6x7wOJzDViXi67Uq7IBVEE0X1GXp24tqrouFVKtbxN/961QhTc93W0aTtpBGQkdhcbNQoVg0s9bNitrideCw0Dvz8Il6vXhUsqGle2dYLDhD+MDqRkVBECppHOJm3q1Rd1O6rTmUBtYf3nqeiUEFHkV02UpfsVh0PWkysgbMxVeqIycrHypNZ4HgXXiRhzc5jaaHie+ERSv33eDz6Gt00PxEXI743FNmh/38VLzCiLlZ3EmXAT+p4sjDLIs39H2n0J5TdVTnCUfBjjJkDQsgsD0qWyevRUEhWBLRZHIEMjtRI37TNr5Rn9umRBw2bioUE1qZ+4mkAJnN2cnQ9rHe2rXtMrwbL3SdQl+aIDgiXWOUdczB1FY8WByO66ReHZu65ivn7dWD9nQOM3wyC2F4Wml6fCb3f0ZCRGNXelNe/bhAmOUBs+lSlfpv7Q==; 5:tRmR2C8ZLEw37HXJqyufo+aZCjCdPKpJeLQfgF2I2aIFH+rO/zUI+WopV7jSbOSLfrVDC2VomAeSHhkMyi4838iWuhtQGBTNb6qSnJgj21rhFM/RACESO0++SZS9ikBEqMq/zWtMfmkj7aF5fyabGJrHiAeNpntA/dDw/CExVNM=; 7:4B+XDqQpyhLBCeBuEAufIERzUVqvi0Iu8mAb43zXntAtDPY75e+/r0NkvauPyNlXrN45YxRfMTmkVa8ZoOw3qVN8tqOEER1+nz2ulbRCnsE1yd1V8LWPPFteXDL3PCoE5Onc+0uwTjuDBQn73B64EiNFgUSeY+2FBkLi3bKKsPGrFhRjVmdB3a6fLWGAVSm5p9A87c9n+wrTTwkCldPkfTHos9/iNbatGoPK8YXhPez0dbBN2j8EguWhbkUkO9gP x-ms-office365-filtering-correlation-id: 76317e07-7624-4a0c-56e5-08d5ed2dacad x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(7020095)(4652040)(8989117)(5600067)(711020)(4618075)(4534165)(4627221)(201703031133081)(201702281549075)(8990107)(2017052603328)(7193020); SRVR:DM5PR2101MB0983; x-ms-traffictypediagnostic: DM5PR2101MB0983: authentication-results: spf=none (sender IP is ) smtp.mailfrom=Christopher.Co@microsoft.com; x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:(28532068793085)(89211679590171)(228905959029699); x-ms-exchange-senderadcheck: 1 x-exchange-antispam-report-cfa-test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(5005006)(8121501046)(93006095)(93001095)(3231311)(944501410)(52105095)(2018427008)(3002001)(10201501046)(6055026)(149027)(150027)(6041310)(20161123562045)(20161123560045)(20161123564045)(20161123558120)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(6072148)(201708071742011)(7699016); SRVR:DM5PR2101MB0983; BCL:0; PCL:0; RULEID:; SRVR:DM5PR2101MB0983; x-forefront-prvs: 0738AF4208 x-forefront-antispam-report: SFV:NSPM; SFS:(10019020)(136003)(396003)(346002)(366004)(376002)(39860400002)(189003)(199004)(25786009)(8936002)(4326008)(16200700003)(53936002)(386003)(53376002)(6506007)(68736007)(52116002)(86612001)(6916009)(76176011)(5640700003)(6512007)(10090500001)(6436002)(106356001)(6306002)(6486002)(14444005)(5660300001)(105586002)(256004)(2351001)(8676002)(53946003)(81166006)(7736002)(305945005)(81156014)(36756003)(478600001)(5250100002)(99286004)(1076002)(19627235002)(14454004)(46003)(54906003)(186003)(2501003)(10290500003)(16799955002)(72206003)(966005)(22452003)(102836004)(486006)(2900100001)(2906002)(6116002)(446003)(2616005)(476003)(316002)(15188155005)(575784001)(86362001)(11346002)(97736004)(559001)(569006); DIR:OUT; SFP:1102; SCL:1; SRVR:DM5PR2101MB0983; H:DM5PR2101MB1128.namprd21.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; MX:1; A:1; received-spf: None (protection.outlook.com: microsoft.com does not designate permitted sender hosts) x-microsoft-antispam-message-info: 9TxGsS0wyNJsFE4jLz8bmlHiF+QoTVXl+kCy6dP32m0UWKZRXJTnVhLsmtIxvGI2AQKiPL6ltu3auJ3ptxUk5lV6hxPJiIaMH+XE2vk8GwsN7Cud/uVV/FEZBarFXt6WD1pNBtjEQIJ9pStG1bv7gPTB3eC0CXssM2zFd22qr0mK3M/UebjtuxSzExv87JRaaI+RaxMoeqf4UXw4TyRo98OWUzC2aBm0jcl7PAwiMCvIUdZRdfT0aVZsitXQxaB2/qsLSmUCs/e/OR6VFpc3tF22sbmvUCU1cS6amSwDv9P4x1K7/3pP11YMKat9Dsj+cT6Ae4Eg7JbEFq9SnjRNK4Qh9IzUI8ZAQKBON+blwOY= spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM MIME-Version: 1.0 X-OriginatorOrg: microsoft.com X-MS-Exchange-CrossTenant-Network-Message-Id: 76317e07-7624-4a0c-56e5-08d5ed2dacad X-MS-Exchange-CrossTenant-originalarrivaltime: 19 Jul 2018 04:11:18.4927 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 72f988bf-86f1-41af-91ab-2d7cd011db47 X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR2101MB0983 Subject: [PATCH edk2-platforms 1/7] Silicon/NXP: Add support for iMX SDHC X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.27 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 19 Jul 2018 04:11:21 -0000 Content-Language: en-US Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable 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 | 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 B= SD 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 IM= PLIED. +* +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +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 eith= er +// CardDetect or WriteProtect +// +typedef enum { + USDHC_SIGNAL_GPIO_START =3D 0x000, + USDHC_SIGNAL_GPIO_END =3D 0xFF00, + USDHC_SIGNAL_OVERRIDE_PIN_LOW =3D 0xFF00, + USDHC_SIGNAL_OVERRIDE_PIN_HIGH =3D 0xFF01, + USDHC_SIGNAL_INTERNAL_PIN =3D 0xFFFF +} USDHC_SIGNAL_SOURCE; + +#define USDHC_IS_GPIO_SIGNAL_SOURCE(X) \ + (((X) >=3D 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 !=3D 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 =3D SdhcCtx->RegistersBase; + + USDHC_BLK_ATT_REG BlkAtt; BlkAtt.AsUint32 =3D MmioRead32((UINTN)&Reg->= BLK_ATT); + UINT32 CmdArg; CmdArg =3D MmioRead32((UINTN)&Reg->CMD_ARG); + USDHC_CMD_XFR_TYP_REG CmdXfrTyp; CmdXfrTyp.AsUint32 =3D MmioRead32((UI= NTN)&Reg->CMD_XFR_TYP); + USDHC_PROT_CTRL_REG ProtCtrl; ProtCtrl.AsUint32 =3D MmioRead32((UINTN)= &Reg->PROT_CTRL); + USDHC_WTMK_LVL_REG WtmkLvl; WtmkLvl.AsUint32 =3D MmioRead32((UINTN)&Re= g->WTMK_LVL); + USDHC_MIX_CTRL_REG MixCtrl; MixCtrl.AsUint32 =3D MmioRead32((UINTN)&Re= g->MIX_CTRL); + UINT32 IntStatusEn =3D MmioRead32((UINTN)&Reg->INT_STATUS_EN); + UINT32 IntSignalEn =3D MmioRead32((UINTN)&Reg->INT_SIGNAL_EN); + UINT32 VendSpec =3D MmioRead32((UINTN)&Reg->VEND_SPEC); + UINT32 MmcBoot =3D MmioRead32((UINTN)&Reg->MMC_BOOT); + UINT32 VendSpec2 =3D MmioRead32((UINTN)&Reg->VEND_SPEC2); + USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 =3D MmioRead32((UIN= TN)&Reg->INT_STATUS); + USDHC_PRES_STATE_REG PresState; PresState.AsUint32 =3D MmioRead32((UIN= TN)&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 CMDT= YP:%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 S= ABGREQ:%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_L= EN:%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 C= EBE:%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 =3D SdhcCtx->RegistersBase; + USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 =3D MmioRead32((UIN= TN)&Reg->INT_STATUS); + UINT32 Retry =3D USDHC_POLL_RETRY_COUNT; + + while (!IntStatus.Fields.BRR && + !(IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) && + Retry) { + --Retry; + gBS->Stall(USDHC_POLL_WAIT_US); + IntStatus.AsUint32 =3D 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 =3D SdhcCtx->RegistersBase; + USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 =3D MmioRead32((UIN= TN)&Reg->INT_STATUS) ; + UINT32 Retry =3D USDHC_POLL_RETRY_COUNT; + + while (!IntStatus.Fields.BWR && + !(IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) && + Retry) { + --Retry; + gBS->Stall(USDHC_POLL_WAIT_US); + IntStatus.AsUint32 =3D 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 spec= ified + // + if (Cmd =3D=3D NULL) { + WaitForDataLine =3D TRUE; + } else { + // + // Per datasheet, the SDHC can isssue CMD0, CMD12, CMD13 and CMD52 + // when the DATA lines are busy during a data transfer. Other comm= ands + // should wait on the DATA lines before issuing + // + switch (Cmd->Index) { + case 0: + case 12: + case 13: + case 52: + WaitForDataLine =3D FALSE; + break; + default: + WaitForDataLine =3D TRUE; + } + } + + USDHC_REGISTERS *Reg =3D SdhcCtx->RegistersBase; + USDHC_PRES_STATE_REG PresState; PresState.AsUint32 =3D MmioRead32((UIN= TN)&Reg->PRES_STATE); + USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 =3D MmioRead32((UIN= TN)&Reg->INT_STATUS) ; + UINT32 Retry =3D 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 =3D MmioRead32((UINTN)&Reg->PRES_STATE); + IntStatus.AsUint32 =3D 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 =3D SdhcCtx->RegistersBase; + USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 =3D MmioRead32((UIN= TN)&Reg->INT_STATUS) ; + UINT32 Retry =3D 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 =3D 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 =3D (USDHC_PRIVATE_CONTEXT*)This->Priva= teContext; + USDHC_REGISTERS *Reg =3D SdhcCtx->RegistersBase; + USDHC_PROT_CTRL_REG ProtCtrl; ProtCtrl.AsUint32 =3D MmioRead32((UINTN)= &Reg->PROT_CTRL); + + LOG_TRACE("SdhcSetBusWidth(%d)", BusWidth); + + switch (BusWidth) { + case SdBusWidth1Bit: + ProtCtrl.Fields.DTW =3D USDHC_PROT_CTRL_DTW_1BIT; + break; + case SdBusWidth4Bit: + ProtCtrl.Fields.DTW =3D USDHC_PROT_CTRL_DTW_4BIT; + break; + case SdBusWidth8Bit: + ProtCtrl.Fields.DTW =3D 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 =3D (USDHC_PRIVATE_CONTEXT*)This->Priva= teContext; + + LOG_TRACE("SdhcSetClock(%dHz)", TargetFreqHz); + + USDHC_REGISTERS *Reg =3D SdhcCtx->RegistersBase; + USDHC_SYS_CTRL_REG SysCtrl; SysCtrl.AsUint32 =3D MmioRead32((UINTN)&Re= g->SYS_CTRL); + + // + // SDCLK =3D (Base Clock) / (prescaler x divisor) + // + UINT32 Prescaler; + UINT32 Divisor; + UINT32 SDCLK; + + USDHC_MIX_CTRL_REG MixCtrl; MixCtrl.AsUint32 =3D MmioRead32((UINTN)&Re= g->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=3D0 |DDR_EN=3D1 + // 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 =3D (MixCtrl.Fields.DDR_EN ? 2 : 1); + const UINT32 PRESCALER_MAX =3D (MixCtrl.Fields.DDR_EN ? 512 : 256);; + const UINT32 DIVISOR_MIN =3D 1; + const UINT32 DIVISOR_MAX =3D 16; + UINT32 MinFreqDistance =3D 0xFFFFFFFF; + UINT32 FreqDistance; + UINT32 BestPrescaler =3D 0; + UINT32 BestDivisor =3D 0; + + // + // Bruteforce to find the best prescaler and divisor that result + // in SDCLK less than or equal to the requested frequency + // + for (Prescaler =3D PRESCALER_MAX; Prescaler >=3D PRESCALER_MIN; Presca= ler /=3D 2) { + for (Divisor =3D DIVISOR_MIN; Divisor <=3D DIVISOR_MAX; ++Divisor)= { + SDCLK =3D 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 =3D=3D TargetFreqHz) { + BestPrescaler =3D Prescaler; + BestDivisor =3D Divisor; + break; + } else { + FreqDistance =3D TargetFreqHz - SDCLK; + if (FreqDistance < MinFreqDistance) { + MinFreqDistance =3D FreqDistance; + BestPrescaler =3D Prescaler; + BestDivisor =3D Divisor; + } + } + } + } + + // + // Wait for clock to become stable before any modifications + // + USDHC_PRES_STATE_REG PresState; PresState.AsUint32 =3D MmioRead32((UIN= TN)&Reg->PRES_STATE); + UINT32 Retry =3D USDHC_POLL_RETRY_COUNT; + + while (!PresState.Fields.SDSTB && + Retry) { + gBS->Stall(USDHC_POLL_WAIT_US); + --Retry; + PresState.AsUint32 =3D 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 =3D MmioRead32((UINTN)&Reg->SYS_CTRL); + SysCtrl.Fields.SDCLKFS =3D BestPrescaler / (MixCtrl.Fields.DDR_EN ? 4 = : 2); + SysCtrl.Fields.DVS =3D BestDivisor - 1; + + MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32); + + SDCLK =3D 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 =3D (USDHC_PRIVATE_CONTEXT*)This->Priva= teContext; + BOOLEAN IsCardPresent; + + if (SdhcCtx->CardDetectSignal =3D=3D USDHC_SIGNAL_INTERNAL_PIN) { + USDHC_REGISTERS *Reg =3D SdhcCtx->RegistersBase; + USDHC_PRES_STATE_REG PresState; PresState.AsUint32 =3D MmioRead32(= (UINTN)&Reg->PRES_STATE); + IsCardPresent =3D (PresState.Fields.CINST =3D=3D 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 =3D + ImxGpioRead( + SdhcCtx->CardDetectGpioPin.Bank, + SdhcCtx->CardDetectGpioPin.IoNumber); + } else if (SdhcCtx->CardDetectSignal =3D=3D USDHC_SIGNAL_OVERRIDE_= PIN_LOW) { + CardDetectLevel =3D IMX_GPIO_LOW; + } else if (SdhcCtx->CardDetectSignal =3D=3D USDHC_SIGNAL_OVERRIDE_= PIN_HIGH) { + CardDetectLevel =3D IMX_GPIO_HIGH; + } else { + ASSERT(!"Invalid CardDetect signal source"); + CardDetectLevel =3D IMX_GPIO_LOW; + } + + // + // When no card is present, CD_B is pulled-high, and the SDCard w= hen + // inserted will pull CD_B low + // CD_B=3D0 means card present, while CD_B=3D1 means card not pres= ent + // + IsCardPresent =3D (CardDetectLevel =3D=3D 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 =3D (USDHC_PRIVATE_CONTEXT*)This->Priva= teContext; + BOOLEAN IsReadOnly; + + if (SdhcCtx->WriteProtectSignal =3D=3D USDHC_SIGNAL_INTERNAL_PIN) { + USDHC_REGISTERS *Reg =3D SdhcCtx->RegistersBase; + USDHC_PRES_STATE_REG PresState; PresState.AsUint32 =3D MmioRead32(= (UINTN)&Reg->PRES_STATE); + IsReadOnly =3D (PresState.Fields.WPSPL =3D=3D 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 =3D + ImxGpioRead( + SdhcCtx->WriteProtectGpioPin.Bank, + SdhcCtx->WriteProtectGpioPin.IoNumber); + } else if (SdhcCtx->WriteProtectSignal =3D=3D USDHC_SIGNAL_OVERRID= E_PIN_LOW) { + WriteProtectLevel =3D IMX_GPIO_LOW; + } else if (SdhcCtx->WriteProtectSignal =3D=3D USDHC_SIGNAL_OVERRID= E_PIN_HIGH) { + WriteProtectLevel =3D IMX_GPIO_HIGH; + } else { + ASSERT(!"Invalid WriteProtect signal source"); + WriteProtectLevel =3D IMX_GPIO_LOW; + } + + // + // When no card is present, WP is pulled-high, and the SDCard whe= n + // inserted will pull WP low if WP switch is configured to write e= nable + // the SDCard, otherwise it WP will stay pulled-high + // WP=3D0 means write enabled, while WP=3D1 means write protected + // + IsReadOnly =3D (WriteProtectLevel !=3D 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 =3D (USDHC_PRIVATE_CONTEXT*)This->Priva= teContext; + USDHC_REGISTERS *Reg =3D SdhcCtx->RegistersBase; + + LOG_TRACE( + "SdhcSendCommand(%cCMD%d, %08x)", + ((Cmd->Class =3D=3D SdCommandClassApp) ? 'A' : ' '), + (UINT32)Cmd->Index, + Argument); + + Status =3D WaitForCmdAndOrDataLine(SdhcCtx, Cmd); + if (Status !=3D 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 =3D { 0 }; + BlkAtt.Fields.BLKSIZE =3D XfrInfo->BlockSize; + ASSERT (XfrInfo->BlockCount > 0); + BlkAtt.Fields.BLKCNT =3D XfrInfo->BlockCount; + MmioWrite32((UINTN)&Reg->BLK_ATT, BlkAtt.AsUint32); + + // + // Set transfer parameters + // + USDHC_MIX_CTRL_REG MixCtrl =3D { 0 }; + if (Cmd->TransferDirection =3D=3D SdTransferDirectionRead) { + MixCtrl.Fields.DTDSEL =3D 1; + } + + if (XfrInfo->BlockCount > 1) { + ASSERT((Cmd->TransferType =3D=3D SdTransferTypeMultiBlock) || + (Cmd->TransferType =3D=3D SdTransferTypeMultiBlockNoStop))= ; + MixCtrl.Fields.MSBSEL =3D 1; + MixCtrl.Fields.BCEN =3D 1; + } + + MmioWrite32((UINTN)&Reg->MIX_CTRL, MixCtrl.AsUint32); + + USDHC_WTMK_LVL_REG WtmkLvl =3D { 0 }; + +#if 0 + // + // Set FIFO watermarks + // + // Configure FIFO watermark levels to 1/2 the FIFO capacity for re= ad, + // 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 =3D=3D SdTransferDirectionRead) { + FifoThresholdWordCount =3D USDHC_FIFO_MAX_WORD_COUNT / 2; + } else { + FifoThresholdWordCount =3D USDHC_FIFO_MAX_WORD_COUNT / 3; + } + + ASSERT(XfrInfo->BlockSize % sizeof(UINT32) =3D=3D 0); + UINT32 TransferByteLength =3D XfrInfo->BlockSize * XfrInfo->BlockC= ount; + const UINT32 TransferWordCount =3D TransferByteLength / sizeof(UIN= T32); + FifoThresholdWordCount =3D MIN(TransferWordCount, FifoThresholdWor= dCount); + + ASSERT(FifoThresholdWordCount <=3D 0xFFFF); + const UINT16 Wml =3D (UINT16)FifoThresholdWordCount; + ASSERT(Wml <=3D USDHC_FIFO_MAX_WORD_COUNT); + + if (Cmd->TransferDirection =3D=3D SdTransferDirectionRead) { + WtmkLvl.Fields.RD_WML =3D (UINT8)Wml; + WtmkLvl.Fields.RD_BRST_LEN =3D MIN(Wml, 8); + } else { + WtmkLvl.Fields.WR_WML =3D (UINT8)Wml; + WtmkLvl.Fields.WR_BRST_LEN =3D MIN(Wml, 8);; + } +#endif + +#if 0 + WtmkLvl.Fields.RD_WML =3D 64; + WtmkLvl.Fields.RD_BRST_LEN =3D 16; + WtmkLvl.Fields.WR_WML =3D 64; + WtmkLvl.Fields.WR_BRST_LEN =3D 16; +#endif + + UINT32 WtmkThreshold =3D USDHC_BLOCK_LENGTH_BYTES / 4; + if (Cmd->TransferDirection =3D=3D SdTransferDirectionRead) { + if (WtmkThreshold > USDHC_WTMK_RD_WML_MAX_VAL) { + WtmkThreshold =3D USDHC_WTMK_RD_WML_MAX_VAL; + } + WtmkLvl.Fields.RD_WML =3D WtmkThreshold; + } else { + if (WtmkThreshold > USDHC_WTMK_WR_WML_MAX_VAL) { + WtmkThreshold =3D USDHC_WTMK_WR_WML_MAX_VAL; + } + WtmkLvl.Fields.WR_WML =3D WtmkThreshold; + } + + MmioWrite32((UINTN)&Reg->WTMK_LVL, WtmkLvl.AsUint32); + } + + // + // Set CMD parameters + // + USDHC_CMD_XFR_TYP_REG CmdXfrTyp =3D { 0 }; + CmdXfrTyp.Fields.CMDINX =3D Cmd->Index; + + switch (Cmd->ResponseType) { + case SdResponseTypeNone: + break; + + case SdResponseTypeR1: + case SdResponseTypeR5: + case SdResponseTypeR6: + CmdXfrTyp.Fields.RSPTYP =3D USDHC_CMD_XFR_TYP_RSPTYP_RSP_48; + CmdXfrTyp.Fields.CICEN =3D 1; + CmdXfrTyp.Fields.CCCEN =3D 1; + break; + + case SdResponseTypeR1B: + case SdResponseTypeR5B: + CmdXfrTyp.Fields.RSPTYP =3D USDHC_CMD_XFR_TYP_RSPTYP_RSP_48_CHK_BS= Y; + CmdXfrTyp.Fields.CICEN =3D 1; + CmdXfrTyp.Fields.CCCEN =3D 1; + break; + + case SdResponseTypeR2: + CmdXfrTyp.Fields.RSPTYP =3D USDHC_CMD_XFR_TYP_RSPTYP_RSP_136; + CmdXfrTyp.Fields.CCCEN =3D 1; + break; + + case SdResponseTypeR3: + case SdResponseTypeR4: + CmdXfrTyp.Fields.RSPTYP =3D USDHC_CMD_XFR_TYP_RSPTYP_RSP_48; + break; + + default: + LOG_ASSERT("SdhcSendCommand(): Invalid response type"); + return EFI_INVALID_PARAMETER; + } + + if (Cmd->Type =3D=3D SdCommandTypeAbort) { + CmdXfrTyp.Fields.CMDTYP =3D USDHC_CMD_XFR_TYP_CMDTYP_ABORT; + } + + if (XfrInfo) { + CmdXfrTyp.Fields.DPSEL =3D 1; + } + + // + // Send command and wait for response + // + MmioWrite32((UINTN)&Reg->CMD_ARG, Argument); + MmioWrite32((UINTN)&Reg->CMD_XFR_TYP, CmdXfrTyp.AsUint32); + + Status =3D 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 =3D (USDHC_PRIVATE_CONTEXT*)This->Priva= teContext; + + if (Buffer =3D=3D NULL) { + LOG_ERROR("Input Buffer is NULL"); + return EFI_INVALID_PARAMETER; + } + + USDHC_REGISTERS *Reg =3D SdhcCtx->RegistersBase; + + switch (Cmd->ResponseType) { + case SdResponseTypeNone: + break; + case SdResponseTypeR1: + case SdResponseTypeR1B: + case SdResponseTypeR3: + case SdResponseTypeR4: + case SdResponseTypeR5: + case SdResponseTypeR5B: + case SdResponseTypeR6: + Buffer[0] =3D MmioRead32((UINTN)&Reg->CMD_RSP0); + LOG_TRACE( + "SdhcReceiveResponse(Type: %x), Buffer[0]: %08x", + Cmd->ResponseType, + Buffer[0]); + break; + case SdResponseTypeR2: + Buffer[0] =3D MmioRead32((UINTN)&Reg->CMD_RSP0); + Buffer[1] =3D MmioRead32((UINTN)&Reg->CMD_RSP1); + Buffer[2] =3D MmioRead32((UINTN)&Reg->CMD_RSP2); + Buffer[3] =3D 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 =3D (USDHC_PRIVATE_CONTEXT*)This->Priva= teContext; + + LOG_TRACE( + "SdhcReadBlockData(LengthInBytes: 0x%x, Buffer: 0x%x)", + LengthInBytes, + Buffer); + + ASSERT(Buffer !=3D NULL); + ASSERT(LengthInBytes % sizeof(UINT32) =3D=3D 0); + + UINTN WordIdx =3D 0; + UINTN NumWords =3D LengthInBytes / sizeof(UINT32); + USDHC_REGISTERS *Reg =3D SdhcCtx->RegistersBase; + USDHC_WTMK_LVL_REG WtmkLvl; WtmkLvl.AsUint32 =3D MmioRead32((UINTN)&Re= g->WTMK_LVL); + UINT32 FifoWords; + EFI_STATUS Status; + + ASSERT(WtmkLvl.Fields.RD_WML > 0); + + while (WordIdx < NumWords) { + Status =3D WaitForReadFifo(SdhcCtx); + if (EFI_ERROR(Status)) { + LOG_ERROR( + "WaitForReadFifo() failed at Word%d. %r", + (UINT32)WordIdx, + Status); + return Status; + } + + FifoWords =3D WtmkLvl.Fields.RD_WML; + while (WordIdx < NumWords && FifoWords--) { + Buffer[WordIdx] =3D 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 =3D (USDHC_PRIVATE_CONTEXT*)This->Priva= teContext; + + LOG_TRACE( + "SdhcWriteBlockData(LengthInBytes: 0x%x, Buffer: 0x%x)", + LengthInBytes, + Buffer); + + ASSERT(Buffer !=3D NULL); + ASSERT(LengthInBytes % USDHC_BLOCK_LENGTH_BYTES =3D=3D 0); + + const UINTN BlockWordCount =3D USDHC_BLOCK_LENGTH_BYTES / sizeof(UINT3= 2); + UINTN NumBlocks =3D LengthInBytes / USDHC_BLOCK_LENGTH_BYTES; + USDHC_REGISTERS *Reg =3D SdhcCtx->RegistersBase; + USDHC_INT_STATUS_REG IntStatus; + USDHC_PRES_STATE_REG PresState; + INT32 Timeout =3D 100000; // Nothing special about that constant + + while (NumBlocks > 0) { + UINTN RemainingWords =3D BlockWordCount; + IntStatus.AsUint32 =3D MmioRead32((UINTN)&Reg->INT_STATUS); + PresState.AsUint32 =3D MmioRead32((UINTN)&Reg->PRES_STATE); + while (!PresState.Fields.BWEN && --Timeout); + if (Timeout <=3D 0) { + LOG_ERROR ("Timeout waiting for FIFO PRES_STATE.BWEN flag"); + return EFI_TIMEOUT; + } + + while (RemainingWords > 0 && !IntStatus.Fields.TC) { + MicroSecondDelay (100); + IntStatus.AsUint32 =3D 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 =3D (USDHC_PRIVATE_CONTEXT*)This->Priva= teContext; + USDHC_REGISTERS *Reg =3D SdhcCtx->RegistersBase; + + UINT32 Retry; + + if (ResetType =3D=3D SdhcResetTypeAll) { + LOG_TRACE("SdhcSoftwareReset(ALL)"); + // + // Software reset for ALL + // + USDHC_SYS_CTRL_REG SysCtrl; SysCtrl.AsUint32 =3D MmioRead32((UINTN= )&Reg->SYS_CTRL); + SysCtrl.Fields.RSTA =3D 1; + MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32); + Retry =3D USDHC_POLL_RETRY_COUNT; + // + // Wait for reset to complete + // + while (SysCtrl.Fields.RSTA && Retry) { + --Retry; + gBS->Stall(USDHC_POLL_WAIT_US); + SysCtrl.AsUint32 =3D 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 =3D WaitForCmdAndOrDataLine(SdhcCtx, NULL); + if (Status !=3D EFI_SUCCESS) { + LOG_ERROR("SdhcWaitForCmdAndDataLine() failed. %r", Status); + return Status; + } + + // + // Send 80 clock ticks to power-up the card + // + SysCtrl.AsUint32 =3D MmioRead32((UINTN)&Reg->SYS_CTRL); + SysCtrl.Fields.INITA =3D 1; + MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32); + Retry =3D 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 =3D 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 =3D MmioRead32((UINTN)&Reg->SYS_CTRL); + SysCtrl.Fields.DTOCV =3D 0xF; + MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32); + + // + // Reset Mixer Control + // + MmioWrite32((UINTN)&Reg->MIX_CTRL, 0); + + USDHC_PROT_CTRL_REG ProtCtrl =3D { 0 }; + ProtCtrl.Fields.EMODE =3D USDHC_PROT_CTRL_EMODE_LITTLE_ENDIAN; + ProtCtrl.Fields.LCTL =3D 1; + MmioWrite32((UINTN)&Reg->PROT_CTRL, ProtCtrl.AsUint32); + + LOG_TRACE("Reset ALL complete"); + + }else if (ResetType =3D=3D SdhcResetTypeCmd) { + LOG_TRACE("SdhcSoftwareReset(CMD)"); + // + // Software reset for CMD + // + USDHC_SYS_CTRL_REG SysCtrl; SysCtrl.AsUint32 =3D MmioRead32((UINTN= )&Reg->SYS_CTRL); + SysCtrl.Fields.RSTC =3D 1; + MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32); + Retry =3D USDHC_POLL_RETRY_COUNT; + + // + // Wait for reset to complete + // + while (SysCtrl.Fields.RSTC && Retry) { + --Retry; + gBS->Stall(USDHC_POLL_WAIT_US); + SysCtrl.AsUint32 =3D 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 =3D=3D SdhcResetTypeData) { + LOG_TRACE("SdhcSoftwareReset(DAT)"); + // + // Software reset for DAT + // + USDHC_SYS_CTRL_REG SysCtrl; SysCtrl.AsUint32 =3D MmioRead32((UINTN= )&Reg->SYS_CTRL); + SysCtrl.Fields.RSTD =3D 1; + MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32); + Retry =3D USDHC_POLL_RETRY_COUNT; + + // + // Wait for reset to complete + // + while (SysCtrl.Fields.RSTD && Retry) { + --Retry; + gBS->Stall(USDHC_POLL_WAIT_US); + SysCtrl.AsUint32 =3D 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 !=3D NULL) { + FreePool(This->PrivateContext); + This->PrivateContext =3D NULL; + } + + FreePool(This); + + // + // Any SDHC protocol call to this instance is illegal beyond this poin= t + // +} + +VOID +SdhcGetCapabilities( + IN EFI_SDHC_PROTOCOL *This, + OUT SDHC_CAPABILITIES *Capabilities + ) +{ + USDHC_PRIVATE_CONTEXT *SdhcCtx =3D (USDHC_PRIVATE_CONTEXT*)This->Priva= teContext; + USDHC_REGISTERS *Reg =3D SdhcCtx->RegistersBase; + + USDHC_HOST_CTRL_CAP_REG Caps; Caps.AsUint32 =3D MmioRead32((UINTN)&Reg= ->HOST_CTRL_CAP); + + Capabilities->MaximumBlockSize =3D (UINT32)(512 << Caps.Fields.MBL); + Capabilities->MaximumBlockCount =3D 0xFFFF; // UINT16_MAX +} + + +EFI_SDHC_PROTOCOL gSdhcProtocolTemplate =3D +{ + 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 =3D NULL; + USDHC_PRIVATE_CONTEXT *SdhcCtx =3D NULL; + + if (ImageHandle =3D=3D NULL || + RegistersBase =3D=3D NULL) { + Status =3D EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Allocate per-device SDHC protocol and private context storage + // + + SdhcProtocol =3D AllocateCopyPool(sizeof(EFI_SDHC_PROTOCOL), &gSdhcPro= tocolTemplate); + if (SdhcProtocol =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + SdhcProtocol->SdhcId =3D SdhcId; + SdhcProtocol->PrivateContext =3D AllocateZeroPool(sizeof(USDHC_PRIVATE= _CONTEXT)); + if (SdhcProtocol->PrivateContext =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + + SdhcCtx =3D (USDHC_PRIVATE_CONTEXT*)SdhcProtocol->PrivateContext; + SdhcCtx->SdhcId =3D SdhcId; + SdhcCtx->RegistersBase =3D (USDHC_REGISTERS*)RegistersBase; + SdhcCtx->CardDetectSignal =3D CardDetectSignal; + if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->CardDetectSignal)) { + SdhcCtx->CardDetectGpioPin.IoNumber =3D PCD_GPIO_PIN_IO_NUMBER((UI= NT16)CardDetectSignal); + SdhcCtx->CardDetectGpioPin.Bank =3D PCD_GPIO_PIN_BANK(CardDetectSi= gnal); + } + + SdhcCtx->WriteProtectSignal=3D WriteProtectSignal; + if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->WriteProtectSignal)) { + SdhcCtx->WriteProtectGpioPin.IoNumber =3D PCD_GPIO_PIN_IO_NUMBER((= UINT16)WriteProtectSignal); + SdhcCtx->WriteProtectGpioPin.Bank =3D PCD_GPIO_PIN_BANK(WriteProte= ctSignal); + } + + 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 =3D gBS->InstallMultipleProtocolInterfaces( + &SdhcCtx->SdhcProtocolHand= le, + &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 !=3D NULL && SdhcProtocol->PrivateContext !=3D NU= LL) { + FreePool(SdhcProtocol->PrivateContext); + SdhcProtocol->PrivateContext =3D NULL; + } + + if (SdhcProtocol !=3D NULL) { + FreePool(SdhcProtocol); + SdhcProtocol =3D NULL; + } + } + + return Status; +} + +EFI_STATUS +SdhcInitialize( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status =3D EFI_SUCCESS; + UINT32 uSdhcRegisteredCount =3D 0; + + // + // Register uSDHC1 through uSDHC4 if their base address is non-zero + // + + // + // uSDHC1 + // + if (FixedPcdGet32(PcdSdhc1Enable)) { + Status =3D uSdhcDeviceRegister( + ImageHandle, + 1, + (VOID*)FixedPcdGet32(PcdSdhc1Base), + FixedPcdGet32(PcdSdhc1CardDetectSignal), + FixedPcdGet32(PcdSdhc1WriteProtectSignal)); + if (!EFI_ERROR(Status)) { + ++uSdhcRegisteredCount; + } + } + + // + // uSDHC2 + // + if (FixedPcdGet32(PcdSdhc2Enable)) { + Status =3D uSdhcDeviceRegister( + ImageHandle, + 2, + (VOID*)FixedPcdGet32(PcdSdhc2Base), + FixedPcdGet32(PcdSdhc2CardDetectSignal), + FixedPcdGet32(PcdSdhc2WriteProtectSignal)); + if (!EFI_ERROR(Status)) { + ++uSdhcRegisteredCount; + } + } + + // + // uSDHC3 + // + if (FixedPcdGet32(PcdSdhc3Enable)) { + Status =3D uSdhcDeviceRegister( + ImageHandle, + 3, + (VOID*)FixedPcdGet32(PcdSdhc3Base), + FixedPcdGet32(PcdSdhc3CardDetectSignal), + FixedPcdGet32(PcdSdhc3WriteProtectSignal)); + if (!EFI_ERROR(Status)) { + ++uSdhcRegisteredCount; + } + } + + // + // uSDHC4 + // + if (FixedPcdGet32(PcdSdhc4Enable)) { + Status =3D 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 !=3D EFI_SUCCESS) && (uSdhcRegisteredCount > 0)) { + Status =3D EFI_SUCCESS; + } + + return Status; +} diff --git a/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf b/Silic= on/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 B= SD 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 IM= PLIED. +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D SdhcDxe + FILE_GUID =3D A9945BAB-78C9-43C9-9175-F576CA189870 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D 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/iMX= PlatformPkg/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 B= SD 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 IM= PLIED. +* +**/ + +#ifndef _IMX_GPIO_H_ +#define _IMX_GPIO_H_ + +#include + +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif // C_ASSERT + +typedef enum { + IMX_GPIO_LOW =3D 0, + IMX_GPIO_HIGH =3D 1 +} IMX_GPIO_VALUE; + +typedef enum { + IMX_GPIO_DIR_INPUT, + IMX_GPIO_DIR_OUTPUT +} IMX_GPIO_DIR; + +typedef enum { + IMX_GPIO_BANK1 =3D 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 GPI= O reg +// +C_ASSERT((FixedPcdGet32(PcdGpioBankMemoryRange) % 4) =3D=3D 0); + +#define GPIO_RESERVED_SIZE \ + ((FixedPcdGet32(PcdGpioBankMemoryRange) / 4) - 8) + +typedef struct { + UINT32 DR; // 0x00 GPIO data register (GPIO= 1_DR) + UINT32 GDIR; // 0x04 GPIO direction register = (GPIO1_GDIR) + UINT32 PSR; // 0x08 GPIO pad status register= (GPIO1_PSR) + UINT32 ICR1; // 0x0C GPIO interrupt configura= tion register1 (GPIO1_ICR1) + UINT32 ICR2; // 0x10 GPIO interrupt configura= tion register2 (GPIO1_ICR2) + UINT32 IMR; // 0x14 GPIO interrupt mask regi= ster (GPIO1_IMR) + UINT32 ISR; // 0x18 GPIO interrupt status re= gister (GPIO1_ISR) + UINT32 EDGE_SEL; // 0x1C GPIO edge select registe= r (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/iM= XPlatformPkg/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 B= SD 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 IM= PLIED. +* +**/ + +#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_I= NT_STATUS_DATA_ERROR) + +#endif // __IMX_USDHC_H__ --=20 2.16.2.gvfs.1.33.gf5370f1