From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=104.47.38.112; helo=nam02-bl2-obe.outbound.protection.outlook.com; envelope-from=christopher.co@microsoft.com; receiver=edk2-devel@lists.01.org Received: from NAM02-BL2-obe.outbound.protection.outlook.com (mail-bl2nam02on0112.outbound.protection.outlook.com [104.47.38.112]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 45C8C211518F1 for ; Fri, 21 Sep 2018 01:26:07 -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=Y/xKtY6KJOdiGifAbnb4ayc4w6BSBIo3lhy5MVj+Kco=; b=PXkmyExUSW4E5cAXm62eelBi17xwrSAKks9kZOmV586ld6Z6pz/aOHycHTpe1e/UitWfd4O44QBXzYbK/pe/bDol2hpHSRCK5UGrVgjY7wFwcA+1W+ctFW6tCLjZ72MncvyvccTfQ8FUchHEEu2QDgMB4Q2p88KB/zmXWrpNQek= Received: from DM5PR2101MB1128.namprd21.prod.outlook.com (52.132.133.20) by DM5PR2101MB0727.namprd21.prod.outlook.com (10.167.110.39) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1185.6; Fri, 21 Sep 2018 08:26:04 +0000 Received: from DM5PR2101MB1128.namprd21.prod.outlook.com ([fe80::81f8:300e:d90:d49]) by DM5PR2101MB1128.namprd21.prod.outlook.com ([fe80::81f8:300e:d90:d49%3]) with mapi id 15.20.1164.008; Fri, 21 Sep 2018 08:26:04 +0000 From: Chris Co To: "edk2-devel@lists.01.org" CC: Ard Biesheuvel , Leif Lindholm , Michael D Kinney Thread-Topic: [PATCH edk2-platforms 13/27] Silicon/NXP: Add support for iMX SDHC Thread-Index: AQHUUYS8FltgGUp3HEGdesBLq9tO/A== Date: Fri, 21 Sep 2018 08:26:04 +0000 Message-ID: <20180921082542.35768-14-christopher.co@microsoft.com> References: <20180921082542.35768-1-christopher.co@microsoft.com> In-Reply-To: <20180921082542.35768-1-christopher.co@microsoft.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: MWHPR17CA0054.namprd17.prod.outlook.com (2603:10b6:300:93::16) To DM5PR2101MB1128.namprd21.prod.outlook.com (2603:10b6:4:a8::20) x-ms-exchange-messagesentrepresentingtype: 1 x-originating-ip: [2001:4898:80e8:8:388a:edc9:7085:c18] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1; DM5PR2101MB0727; 6:JtbxM6Uh9sQP4xRREifZ9Wr/zDNMVDL6mqaFv1vuk9ulrlktSc/UGsfFac67dGj/MN8YVzHJva4er9p8BiaozStdvfn8ACHPtvhbi/rFdYvitmbpDsiPy8W6/+mnZzUIjEzz6X/8Fv9wUz+l2H7iXSV5cReDbmGhJullNWlYP7odilrBJpNF7VLn3Nq61SflwlK3718Z1rQNZ462OL4nPYGUCRcmSUZgWbY08y0qns3xAtuscAWIuv1vxkSLMMRSEH0w7Cgerur6JfqmQbjE/AXynG1tpg1EhUWzB7G2r58Oap9c4YTPBgPsxT0fo+rQolVnAGODyeJgH9AAIsUvM0FsPR5pgv6Whv9ogITItBRPmJq0JHzpHXZymO49oHEryvulSIvYfkzfp+9kcjTthg94VwfVi2oQoSwRCEwvGz9QavMKT20YH3dHrEoozeE7qH1+yOZjjkeQAOIUXAhZ8w==; 5:zXOeE99oOSxsP1b6psVIRFScXY2EgaJN3+8RkhfRlA1OEuS4bs0SFLzc4JUCL3R/heSGGW7uIRTt5SZ3MQblmeAuIZkHYLwuh3cIdHutBaTtucPttJySr+4jCR/hHP2Zq6NuNkmLlzEIMZIaSZLr5qheWJSivRitMmwtp6qFQL8=; 7:8SP93ZIPMSEKThUHzjsyaHdNSLJujw1TAEXZOo6QKprNKumLyHUXvIlQiLHGbbjRiTB6LGBTKUe8KFZ+Kcj2jvuZUFLF7vSCUC22eTZwQJsaKfyPJ13w/36FWMYrGCfNbreAZ00h83HegTnOEptA5M0TLuX3nC+3IJSHitPV519iVQmHKqXyqAnsWftr4RuAFvXIRvi0bf/zOlwsw24fkfnqUZ4Yrh+Xf+EWut5TjJdw55tjbUwuIJvSEL6hSVPG x-ms-office365-filtering-correlation-id: 9e5329ad-d1af-4285-b78d-08d61f9bdefd x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(7020095)(4652040)(8989299)(4534165)(4627221)(201703031133081)(201702281549075)(8990200)(5600074)(711020)(4618075)(2017052603328)(7193020); SRVR:DM5PR2101MB0727; x-ms-traffictypediagnostic: DM5PR2101MB0727: x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:(105169848403564)(28532068793085)(89211679590171)(12401385986421)(228905959029699); x-ms-exchange-senderadcheck: 1 x-exchange-antispam-report-cfa-test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(8121501046)(5005006)(3231355)(2280164)(944501410)(52105095)(2018427008)(93006095)(93001095)(3002001)(10201501046)(6055026)(149027)(150027)(6041310)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123562045)(20161123560045)(20161123564045)(20161123558120)(201708071742011)(7699051)(76991041); SRVR:DM5PR2101MB0727; BCL:0; PCL:0; RULEID:; SRVR:DM5PR2101MB0727; x-forefront-prvs: 0802ADD973 x-forefront-antispam-report: SFV:NSPM; SFS:(10019020)(1496009)(39860400002)(396003)(136003)(376002)(366004)(346002)(199004)(189003)(8676002)(81156014)(25786009)(446003)(2900100001)(102836004)(46003)(52116002)(6346003)(81166006)(11346002)(105586002)(2351001)(8936002)(386003)(4326008)(76176011)(6506007)(10090500001)(5250100002)(7736002)(2616005)(486006)(305945005)(53376002)(6116002)(186003)(16799955002)(1076002)(2501003)(476003)(6916009)(99286004)(22452003)(97736004)(45954006)(71200400001)(71190400001)(72206003)(478600001)(966005)(6306002)(10290500003)(5640700003)(14454004)(36756003)(86362001)(19627235002)(575784001)(6436002)(16200700003)(15188155005)(2906002)(53946003)(86612001)(106356001)(54906003)(316002)(6486002)(256004)(6512007)(14444005)(68736007)(5660300001)(53936002)(60540400001)(579004)(569006); DIR:OUT; SFP:1102; SCL:1; SRVR:DM5PR2101MB0727; H:DM5PR2101MB1128.namprd21.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; A:1; MX:1; received-spf: None (protection.outlook.com: microsoft.com does not designate permitted sender hosts) authentication-results: spf=none (sender IP is ) smtp.mailfrom=Christopher.Co@microsoft.com; x-microsoft-antispam-message-info: cLyPk6hQPJUByyZT7kq0W3GkhGTL6vU1I6r3jiMpzFvuh/lAJTR8fFXbKladqDsLnaZM+wpv2wW3kCcM6dn8PGiVcYR7/RYpng4bHtHanJTVXOcdM5dIolNTI67xGUR8VKrTfk8ePExtl51S2w/lAjZuwLyRghjoT62E0p7wK5zaSyHZxQ8W/2DTDdsxrRJ06L5RLfiZu62j1us3D3C88Y1JAlirmgCVpL4nLsoGO8AurvWJZqCArhJt1aREk9IZeaBwz7uJqP0VT2hWG8NzXrG+M7TzbwHTaSbR96hyD8R2eo7By4EM8tUCIpR4NUm4GFV9GzBZ5UtL+DZ00EWKY6AblUL5z8RYcrf6AwQpje3IToVs49sWTSaagu9hlztmr69JacGdQcIZnDe46hZcElocOKbIvmTQZQtOYR/wEerE1Vg02FO2rJwN8M6NmhAaZsMWz42soob0qoOgSk569N5fnDOg267xfiQlVR7qAyNxlAat1YGzXxEwX9v1MdDMu/5GcHmd6/pjUMKFpiGBiHNtiehKCwUOUNhw53jSAdIpWn1sz0blVRY3qCBUZ8yL spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM MIME-Version: 1.0 X-OriginatorOrg: microsoft.com X-MS-Exchange-CrossTenant-Network-Message-Id: 9e5329ad-d1af-4285-b78d-08d61f9bdefd X-MS-Exchange-CrossTenant-originalarrivaltime: 21 Sep 2018 08:26:04.6065 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 72f988bf-86f1-41af-91ab-2d7cd011db47 X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR2101MB0727 Subject: [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: Fri, 21 Sep 2018 08:26:07 -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 | 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 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 +#include "SdhcDxe.h" + +VOID +DumpState ( + IN USDHC_PRIVATE_CONTEXT *SdhcCtx + ) +{ + DEBUG_CODE_BEGIN (); + + USDHC_REGISTERS *Reg; + 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 =3D SdhcCtx->RegistersBase; + BlkAtt.AsUint32 =3D MmioRead32 ((UINTN)&Reg->BLK_ATT); + CmdArg =3D MmioRead32 ((UINTN)&Reg->CMD_ARG); + CmdXfrTyp.AsUint32 =3D MmioRead32 ((UINTN)&Reg->CMD_XFR_TYP); + ProtCtrl.AsUint32 =3D MmioRead32 ((UINTN)&Reg->PROT_CTRL); + WtmkLvl.AsUint32 =3D MmioRead32 ((UINTN)&Reg->WTMK_LVL); + MixCtrl.AsUint32 =3D MmioRead32 ((UINTN)&Reg->MIX_CTRL); + IntStatusEn =3D MmioRead32 ((UINTN)&Reg->INT_STATUS_EN); + IntSignalEn =3D MmioRead32 ((UINTN)&Reg->INT_SIGNAL_EN); + VendSpec =3D MmioRead32 ((UINTN)&Reg->VEND_SPEC); + MmcBoot =3D MmioRead32 ((UINTN)&Reg->MMC_BOOT); + VendSpec2 =3D MmioRead32 ((UINTN)&Reg->VEND_SPEC2); + IntStatus.AsUint32 =3D MmioRead32 ((UINTN)&Reg->INT_STATUS); + PresState.AsUint32 =3D 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 SABGR= EQ:%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 A= C23EN:%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 =3D SdhcCtx->RegistersBase; + IntStatus.AsUint32 =3D MmioRead32 ((UINTN)&Reg->INT_STATUS); + 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; + USDHC_INT_STATUS_REG IntStatus; + UINT32 Retry; + + Reg =3D SdhcCtx->RegistersBase; + IntStatus.AsUint32 =3D MmioRead32 ((UINTN)&Reg->INT_STATUS) ; + 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 + ) +{ + 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 specif= ied + 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 commands + // 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; + } + } + + Reg =3D SdhcCtx->RegistersBase; + PresState.AsUint32 =3D MmioRead32 ((UINTN)&Reg->PRES_STATE); + IntStatus.AsUint32 =3D MmioRead32 ((UINTN)&Reg->INT_STATUS) ; + 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; + USDHC_INT_STATUS_REG IntStatus; + UINT32 Retry; + + Reg =3D SdhcCtx->RegistersBase; + IntStatus.AsUint32 =3D MmioRead32 ((UINTN)&Reg->INT_STATUS) ; + 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_REGISTERS *Reg; + USDHC_PRIVATE_CONTEXT *SdhcCtx; + USDHC_PROT_CTRL_REG ProtCtrl; + + SdhcCtx =3D (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; + Reg =3D SdhcCtx->RegistersBase; + 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_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 =3D (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; + LOG_TRACE ("SdhcSetClock(%dHz)", TargetFreqHz); + + Reg =3D SdhcCtx->RegistersBase; + SysCtrl.AsUint32 =3D MmioRead32 ((UINTN)&Reg->SYS_CTRL); + + // SdClk =3D (Base Clock) / (prescaler x divisor) + MixCtrl.AsUint32 =3D 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=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; + MinFreqDistance =3D MAX_UINT32; + BestPrescaler =3D 0; + 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; Prescale= r /=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 + PresState.AsUint32 =3D MmioRead32 ((UINTN)&Reg->PRES_STATE); + 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_REGISTERS *Reg; + USDHC_PRIVATE_CONTEXT *SdhcCtx; + IMX_GPIO_VALUE CardDetectLevel; + BOOLEAN IsCardPresent; + USDHC_PRES_STATE_REG PresState; + + SdhcCtx =3D (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; + if (SdhcCtx->CardDetectSignal =3D=3D USDHC_SIGNAL_INTERNAL_PIN) { + Reg =3D SdhcCtx->RegistersBase; + PresState.AsUint32 =3D MmioRead32 ((UINTN)&Reg->PRES_STATE); + IsCardPresent =3D (PresState.Fields.CINST =3D=3D 1); + } else { + 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 when + // inserted will pull CD_B low + // CD_B=3D0 means card present, while CD_B=3D1 means card not present + IsCardPresent =3D (CardDetectLevel =3D=3D 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 =3D (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; + + if (SdhcCtx->WriteProtectSignal =3D=3D USDHC_SIGNAL_INTERNAL_PIN) { + Reg =3D SdhcCtx->RegistersBase; + PresState.AsUint32 =3D MmioRead32 ((UINTN)&Reg->PRES_STATE); + IsReadOnly =3D (PresState.Fields.WPSPL =3D=3D 0); + } else { + 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_OVERRIDE_PI= N_LOW) { + WriteProtectLevel =3D IMX_GPIO_LOW; + } else if (SdhcCtx->WriteProtectSignal =3D=3D USDHC_SIGNAL_OVERRIDE_PI= N_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 when + // inserted will pull WP low if WP switch is configured to write enabl= e + // 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 + ) +{ + 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 =3D (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; + 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 + BlkAtt.AsUint32 =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 + MixCtrl.AsUint32 =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); + + WtmkLvl.AsUint32 =3D 0; + + 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 + CmdXfrTyp.AsUint32 =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_BSY; + 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_REGISTERS *Reg; + USDHC_PRIVATE_CONTEXT *SdhcCtx; + + SdhcCtx =3D (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; + + if (Buffer =3D=3D NULL) { + LOG_ERROR ("Input Buffer is NULL"); + return EFI_INVALID_PARAMETER; + } + + 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_REGISTERS *Reg; + USDHC_PRIVATE_CONTEXT *SdhcCtx; + UINT32 FifoWords; + UINTN NumWords; + EFI_STATUS Status; + UINTN WordIdx; + USDHC_WTMK_LVL_REG WtmkLvl; + + SdhcCtx =3D (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; + + LOG_TRACE ( + "SdhcReadBlockData(LengthInBytes: 0x%x, Buffer: 0x%x)", + LengthInBytes, + Buffer); + + ASSERT (Buffer !=3D NULL); + ASSERT (LengthInBytes % sizeof (UINT32) =3D=3D 0); + + WordIdx =3D 0; + NumWords =3D LengthInBytes / sizeof (UINT32); + Reg =3D SdhcCtx->RegistersBase; + WtmkLvl.AsUint32 =3D MmioRead32 ((UINTN)&Reg->WTMK_LVL); + + 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_REGISTERS *Reg; + USDHC_PRIVATE_CONTEXT *SdhcCtx; + USDHC_INT_STATUS_REG IntStatus; + UINTN NumBlocks; + USDHC_PRES_STATE_REG PresState; + UINTN RemainingWords; + INT32 Retry; + + SdhcCtx =3D (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; + + 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 (UINT32= ); + NumBlocks =3D LengthInBytes / USDHC_BLOCK_LENGTH_BYTES; + Reg =3D SdhcCtx->RegistersBase; + Retry =3D 100000; + + while (NumBlocks > 0) { + RemainingWords =3D BlockWordCount; + IntStatus.AsUint32 =3D MmioRead32 ((UINTN)&Reg->INT_STATUS); + PresState.AsUint32 =3D MmioRead32 ((UINTN)&Reg->PRES_STATE); + while (!PresState.Fields.BWEN && --Retry); + if (Retry <=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_REGISTERS *Reg; + USDHC_PRIVATE_CONTEXT *SdhcCtx; + USDHC_PROT_CTRL_REG ProtCtrl; + UINT32 Retry; + EFI_STATUS Status; + USDHC_SYS_CTRL_REG SysCtrl; + + SdhcCtx =3D (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; + Reg =3D SdhcCtx->RegistersBase; + + if (ResetType =3D=3D SdhcResetTypeAll) { + LOG_TRACE ("SdhcSoftwareReset(ALL)"); + // Software reset for ALL + 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 + 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); + + ProtCtrl.AsUint32 =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 + // + 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 + 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); +} + +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 =3D (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; + Reg =3D SdhcCtx->RegistersBase; + Caps.AsUint32 =3D MmioRead32 ((UINTN)&Reg->HOST_CTRL_CAP); + Capabilities->MaximumBlockSize =3D (UINT32) (512 << Caps.Fields.MBL); + Capabilities->MaximumBlockCount =3D 0xFFFF; +} + +static EFI_SDHC_PROTOCOL mSdhcProtocolTemplate =3D { + 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 =3D NULL; + 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), + &mSdhcProtocolTemplate); + 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 (( + UINT16)CardDetectSignal); + SdhcCtx->CardDetectGpioPin.Bank =3D PCD_GPIO_PIN_BANK (CardDetectSigna= l); + } + + 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 (WriteProtectS= ignal); + } + + 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->SdhcProtocolHandle, + &gEfiSdhcProtocolGuid, + SdhcProtocol, + NULL); + if (EFI_ERROR (Status)) { + LOG_ERROR ("InstallMultipleProtocolInterfaces failed. %r", Status); + goto Exit; + } + +Exit: + if (EFI_ERROR (Status)) { + LOG_ERROR ("Failed to register and initialize uSDHC%d", SdhcId); + + if (SdhcProtocol !=3D NULL && SdhcProtocol->PrivateContext !=3D NULL) = { + 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 + ) +{ + UINT32 SdhcRegisteredCount; + EFI_STATUS Status; + + Status =3D EFI_SUCCESS; + SdhcRegisteredCount =3D 0; + + // Register uSDHC1 through uSDHC4 if their base address is non-zero + + // uSDHC1 + if (FixedPcdGet32 (PcdSdhc1Enable)) { + Status =3D SdhcDeviceRegister ( + ImageHandle, + 1, + (VOID *)FixedPcdGet32 (PcdSdhc1Base), + FixedPcdGet32 (PcdSdhc1CardDetectSignal), + FixedPcdGet32 (PcdSdhc1WriteProtectSignal)); + if (!EFI_ERROR (Status)) { + ++SdhcRegisteredCount; + } + } + + // uSDHC2 + if (FixedPcdGet32 (PcdSdhc2Enable)) { + Status =3D SdhcDeviceRegister ( + ImageHandle, + 2, + (VOID *)FixedPcdGet32 (PcdSdhc2Base), + FixedPcdGet32 (PcdSdhc2CardDetectSignal), + FixedPcdGet32 (PcdSdhc2WriteProtectSignal)); + if (!EFI_ERROR (Status)) { + ++SdhcRegisteredCount; + } + } + + // uSDHC3 + if (FixedPcdGet32 (PcdSdhc3Enable)) { + Status =3D SdhcDeviceRegister ( + ImageHandle, + 3, + (VOID *)FixedPcdGet32 (PcdSdhc3Base), + FixedPcdGet32 (PcdSdhc3CardDetectSignal), + FixedPcdGet32 (PcdSdhc3WriteProtectSignal)); + if (!EFI_ERROR (Status)) { + ++SdhcRegisteredCount; + } + } + + // uSDHC4 + if (FixedPcdGet32 (PcdSdhc4Enable)) { + Status =3D SdhcDeviceRegister ( + ImageHandle, + 4, + (VOID *)FixedPcdGet32 (PcdSdhc4Base), + FixedPcdGet32 (PcdSdhc4CardDetectSignal), + FixedPcdGet32 (PcdSdhc4WriteProtectSignal)); + if (!EFI_ERROR (Status)) { + ++SdhcRegisteredCount; + } + } + + // Succeed driver loading if at least one enabled uSDHC got registered s= uccessfully + if ((Status !=3D EFI_SUCCESS) && (SdhcRegisteredCount > 0)) { + Status =3D 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 @@ -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 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 _SDHC_DXE_H_ +#define _SDHC_DXE_H_ + +typedef struct { + UINT32 IoNumber; + IMX_GPIO_BANK Bank; +} IMX_GPIO_PIN; + +#define PCD_GPIO_PIN_IO_NUMBER(X) ((X) & 0xFF) +#define PCD_GPIO_PIN_BANK(X) (((X) >> 8) & 0xFF) + +// A special value to indicate that GPIO is not the signal source for 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") + +// 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/Silic= on/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 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 0x0001001A + 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] + 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/iM= XPlatformPkg/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 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