From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=104.47.42.95; helo=nam03-by2-obe.outbound.protection.outlook.com; envelope-from=christopher.co@microsoft.com; receiver=edk2-devel@lists.01.org Received: from NAM03-BY2-obe.outbound.protection.outlook.com (mail-by2nam03on0095.outbound.protection.outlook.com [104.47.42.95]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 65DA920988779 for ; Mon, 16 Jul 2018 19:05:47 -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=hdkA+oRK3if0lol++Z9gkGf7YHQKpvluPxT5HYOkZqg=; b=kHCpoEan7Coa5xwcRZXA8bnIO+e/psdQhcjEnJf56jwjr52anXyHxIl0Rs/i5Q0UfaMRvtDuFye5S11bVNsT7L50IPBc6dh7OBltkrF38Qk0XNReqgvSC2IwETlEGOVgq+qor+FsWoIXf1oPAOmDx2u5FIBaD/T0xza7AEwUfd4= Received: from DM5PR2101MB1128.namprd21.prod.outlook.com (52.132.133.20) by DM5PR2101MB1062.namprd21.prod.outlook.com (52.132.128.19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.995.1; Tue, 17 Jul 2018 02:05:42 +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.004; Tue, 17 Jul 2018 02:05:42 +0000 From: Chris Co To: "edk2-devel@lists.01.org" CC: Ard Biesheuvel , Leif Lindholm , Michael D Kinney Thread-Topic: [PATCH edk2-platforms 1/3] Platform/Microsoft: Add SdMmc Dxe Driver Thread-Index: AQHUHXKql0LJjOelxkSqfeJnGz+aow== Date: Tue, 17 Jul 2018 02:05:42 +0000 Message-ID: <20180717020529.19496-2-christopher.co@microsoft.com> References: <20180717020529.19496-1-christopher.co@microsoft.com> In-Reply-To: <20180717020529.19496-1-christopher.co@microsoft.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: SN2PR01CA0041.prod.exchangelabs.com (2603:10b6:804:2::51) To DM5PR2101MB1128.namprd21.prod.outlook.com (2603:10b6:4:a8::20) x-ms-exchange-messagesentrepresentingtype: 1 x-originating-ip: [2001:4898:80e8:9:79cf:d6d4:d0ef:f79b] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1; DM5PR2101MB1062; 6:r2rUlA5jxmByXXyXuqtfBSnOKx2XKRbNp4DaMarAbHWsqo0bFDXi3yINeqL8+jifcJUNsRBuT4FDCkZ1sFklA8yfNzgkUCqX8qwPrpZBCqWHAOblJMljinipemyrzo/m6z6lplQj6dKJYBxrAaA9jvXne/3xC8uzI8xiEZ30cfUS8NyZL7cnhY4TPdcJkwlJBFHGsrJX57dmYV69tlVpxOv/5TgxFuKrmYD6RUswIN3vJPcWx1aDbMnEp+UV1opIqxpmUPbioZl1fxN7a7FqL+jEOvJJ7Lm3wJP2LnLDoKxh5SJHigu/G/7arIyoShl8LSRPq2599igYfmoQ9nLl5YeV4PHBB4KU9PFjiBalhQUpwrc1yw0LmxZWDkdyn9GXLEMGisI4j10BUM7kFbeKOZbPGU1K95F3rCNld+YQddHN2UgVp3xt58URBipxgYG+QJ8w8nuPzBU1ifOFB30IHw==; 5:d5ut788WdSE1yp61EvrMi2OojC/PyloBtTcQdlModpnNmQmgI8nUDW2d+O0s+ZNYrYa5RjEq69Mn5E84fqD/q5Y1tHLXJB6y9i53y5SQpWbSW0EWu8d++ObCpEhMIiFTFdNyH1bqHW66o8T7an/trzb1DNAzqeBrPgn7T4DY/qk=; 7:yDZERsEgWFMNIXR2/gMULcnvObXcke6YbqW+V1X+MOe089mxHtVVRbF5jX6IZge+y15vLDruQJfZ0HIMak9ZribTWqcQS+54bicZTYYDsgodrgbcii9BoDNDqUrWcxg1nKKEOCtKboEye1yi7615EE+EEqTNcIG0o1XzKpSwhTWM8BBE1nV+wCDbbMMrX5eym3uaiwlU2x+7PcMv+rHD/+YAstkl8aL3BOd2Son5gvUs/nZOqQOysRXKdpMUlHYZ x-ms-office365-filtering-correlation-id: 75d939ed-bb49-4fc8-b006-08d5eb89cc29 x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: UriScan:; BCL:0; PCL:0; RULEID:(7020095)(4652040)(8989117)(5600053)(711020)(4534165)(4627221)(201703031133081)(201702281549075)(8990107)(48565401081)(2017052603328)(7193020); SRVR:DM5PR2101MB1062; x-ms-traffictypediagnostic: DM5PR2101MB1062: authentication-results: spf=none (sender IP is ) smtp.mailfrom=Christopher.Co@microsoft.com; x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:(28532068793085)(60795455431006)(89211679590171)(211171220733660)(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)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123560045)(20161123558120)(20161123564045)(20161123562045)(6072148)(201708071742011)(7699016); SRVR:DM5PR2101MB1062; BCL:0; PCL:0; RULEID:; SRVR:DM5PR2101MB1062; x-forefront-prvs: 073631BD3D x-forefront-antispam-report: SFV:NSPM; SFS:(10019020)(6029001)(366004)(346002)(376002)(396003)(39860400002)(136003)(47530400004)(40224003)(189003)(199004)(52116002)(16799955002)(256004)(53376002)(15188155005)(86362001)(86612001)(575784001)(2501003)(5250100002)(53936002)(76176011)(386003)(6506007)(68736007)(7736002)(102836004)(186003)(19627235002)(2906002)(46003)(1076002)(6116002)(53946003)(6512007)(6306002)(54906003)(16200700003)(22452003)(14444005)(305945005)(99286004)(316002)(11346002)(486006)(5640700003)(6486002)(2616005)(25786009)(2900100001)(72206003)(106356001)(97736004)(4326008)(10090500001)(2351001)(105586002)(478600001)(8936002)(81156014)(81166006)(14454004)(966005)(6916009)(8676002)(10290500003)(36756003)(5660300001)(446003)(6436002)(476003)(579004)(569006); DIR:OUT; SFP:1102; SCL:1; SRVR:DM5PR2101MB1062; 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: s9Dq3PxNS1H4tJhY5SHDZKO076sWAWmqMIPVFvy3TAUsNbGjUklgYqED/7iU5xA6hajjdIe19LBm27ES61Tf4rgnk6fwgrsO6dfIR5jO7VBXDyecXXjZj7ub9bphl2SfRt1Lxa3sgd6wODs4n1oqYhyZsYigSAAKXluHRMoA5NVWwIwUKTo5z88334SdxdAYIdsj2viTdkrZvlxpcJw024g/psK+os8uhYFRQSPKdsVB3X69JSLsnAYzQcb1gUkQC3Rf7AIcjr7kAmZa4HblN26kuJ+Exc/6Tm2wTaoPfu1u6/C7k1hMopFFqVnYQ78P/trrXlN4o/m4M+NIA4xSCm1I5ATAOO0+AfJBkjWRYuE= spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM MIME-Version: 1.0 X-OriginatorOrg: microsoft.com X-MS-Exchange-CrossTenant-Network-Message-Id: 75d939ed-bb49-4fc8-b006-08d5eb89cc29 X-MS-Exchange-CrossTenant-originalarrivaltime: 17 Jul 2018 02:05:42.7061 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 72f988bf-86f1-41af-91ab-2d7cd011db47 X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR2101MB1062 Subject: [PATCH edk2-platforms 1/3] Platform/Microsoft: Add SdMmc Dxe Driver 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: Tue, 17 Jul 2018 02:05:47 -0000 Content-Language: en-US Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable This SdMmc driver adds support to boot Windows from SD and eMMC. It implements RPMB protocol support for eMMC, unique device path creation for each slot on the SD bus, high speed modes, eMMC bus width auto-detection, and support for high capacity SDXC cards. Derived from: EmbeddedPkg\Universal\MmcDxe Cc: Ard Biesheuvel Cc: Leif Lindholm Cc: Michael D Kinney Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Christopher Co --- Platform/Microsoft/Drivers/SdMmcDxe/BlockIo.c | 526 ++++++ Platform/Microsoft/Drivers/SdMmcDxe/Debug.c | 358 ++++ Platform/Microsoft/Drivers/SdMmcDxe/Protocol.c | 1774 ++++++++++++++++++= ++ Platform/Microsoft/Drivers/SdMmcDxe/Protocol.h | 231 +++ Platform/Microsoft/Drivers/SdMmcDxe/RpmbIo.c | 611 +++++++ Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.c | 892 ++++++++++ Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.h | 529 ++++++ Platform/Microsoft/Drivers/SdMmcDxe/SdMmcDxe.inf | 50 + Platform/Microsoft/Drivers/SdMmcDxe/SdMmcHw.h | 506 ++++++ Platform/Microsoft/Include/Protocol/RpmbIo.h | 262 +++ Platform/Microsoft/Include/Protocol/Sdhc.h | 197 +++ 11 files changed, 5936 insertions(+) diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/BlockIo.c b/Platform/Micro= soft/Drivers/SdMmcDxe/BlockIo.c new file mode 100644 index 000000000000..07acd7b7b3f7 --- /dev/null +++ b/Platform/Microsoft/Drivers/SdMmcDxe/BlockIo.c @@ -0,0 +1,526 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Copyright (c) 2011-2014, ARM Limited. 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 "SdMmcHw.h" +#include "SdMmc.h" +#include "Protocol.h" + +VOID +BenchmarkIo ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN SD_TRANSFER_DIRECTION TransferDirection, + IN UINT32 MediaId, + IN UINTN BufferSize, + IN UINT32 Iterations + ); + +EFI_STATUS +IoBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN SD_TRANSFER_DIRECTION TransferDirection, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN OUT VOID *Buffer + ); + +VOID +SortIoReadStatsByTotalTransferTime ( + IN IoReadStatsEntry* Table, + IN UINT32 NumEntries + ) +{ + // Using the simple insertion sort + UINT32 Idx; + for (Idx =3D 1; Idx < NumEntries; ++Idx) { + IoReadStatsEntry CurrEntry =3D Table[Idx]; + UINT32 J =3D Idx; + while (J > 0 && + Table[J - 1].TotalTransferTimeUs < CurrEntry.TotalTransferTimeU= s) { + Table[J] =3D Table[J - 1]; + --J; + } + Table[J] =3D CurrEntry; + } +} + +VOID +BenchmarkIo ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN SD_TRANSFER_DIRECTION TransferDirection, + IN UINT32 MediaId, + IN UINTN BufferSize, + IN UINT32 Iterations + ) +{ + ASSERT (Iterations > 0); + + EFI_STATUS Status; + UINT32 BufferSizeKB =3D INT_DIV_ROUND (BufferSize, 1024); + VOID* Buffer =3D AllocateZeroPool (BufferSize); + if (Buffer =3D=3D NULL) { + LOG_ERROR ("BenchmarkIo() : No enough memory to allocate %dKB buffer",= BufferSizeKB); + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + + UINT32 CurrIteration =3D Iterations; + UINT64 TotalTransfersTimeUs =3D 0; + + while (CurrIteration--) { + UINT64 StartTime =3D GetPerformanceCounter (); + + Status =3D IoBlocks ( + This, + TransferDirection, + MediaId, + 0, // Lba + BufferSize, + Buffer + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + UINT64 EndTime =3D GetPerformanceCounter (); + TotalTransfersTimeUs +=3D (((EndTime - StartTime) * 1000000UL) / gHpcT= icksPerSeconds); + } + + UINT32 KBps =3D (UINT32) (((UINT64) BufferSizeKB * (UINT64) Iterations *= 1000000UL) / TotalTransfersTimeUs); + LOG_INFO ( + "- BenchmarkIo(%a, %dKB)\t: Xfr Avg:%dus\t%dKBps\t%dMBps", + (TransferDirection =3D=3D SdTransferDirectionRead) ? "Read" : "Write", + BufferSizeKB, + (UINT32) (TotalTransfersTimeUs / Iterations), + KBps, + INT_DIV_ROUND (KBps, 1024)); + +Exit: + if (Buffer !=3D NULL) { + FreePool (Buffer); + } +} + +EFI_STATUS +IoBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN SD_TRANSFER_DIRECTION TransferDirection, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN OUT VOID *Buffer + ) +{ + SDHC_INSTANCE *HostInst; + EFI_STATUS Status; + CONST SD_COMMAND *Cmd; + UINT32 BlockCount; + + HostInst =3D SDHC_INSTANCE_FROM_BLOCK_IO_THIS (This); + ASSERT (HostInst); + ASSERT (HostInst->HostExt); + + if (This->Media->MediaId !=3D MediaId) { + Status =3D EFI_MEDIA_CHANGED; + goto Exit; + } + + if (Buffer =3D=3D NULL) { + Status =3D EFI_INVALID_PARAMETER; + goto Exit; + } + + // Check if a Card is Present + if (!HostInst->BlockIo.Media->MediaPresent) { + Status =3D EFI_NO_MEDIA; + goto Exit; + } + + // Reading 0 Byte is valid + if (BufferSize =3D=3D 0) { + Status =3D EFI_SUCCESS; + goto Exit; + } + + if ((TransferDirection =3D=3D SdTransferDirectionWrite) && (This->Media-= >ReadOnly =3D=3D TRUE)) { + Status =3D EFI_WRITE_PROTECTED; + goto Exit; + } + + // The buffer size must be an exact multiple of the block size + if ((BufferSize % This->Media->BlockSize) !=3D 0) { + Status =3D EFI_BAD_BUFFER_SIZE; + goto Exit; + } + + BlockCount =3D BufferSize / This->Media->BlockSize; + + // All blocks must be within the device + if ((Lba + BlockCount - 1) > (This->Media->LastBlock)) { + LOG_ERROR ( + "Data span is out of media address range. (Media Last Block LBA =3D = 0x%lx" + "Data Last Block LBA =3D 0x%lx)", + This->Media->LastBlock, + (Lba + BlockCount - 1)); + + Status =3D EFI_INVALID_PARAMETER; + goto Exit; + } + + // Check the alignment + if ((This->Media->IoAlign > 2) && (((UINTN) Buffer & (This->Media->IoAli= gn - 1)) !=3D 0)) { + LOG_ERROR ( + "Invalid buffer address alignment (Buffer =3D %p, IoAlign =3D %d)", + Buffer, + This->Media->IoAlign); + + Status =3D EFI_INVALID_PARAMETER; + goto Exit; + } + + if (TransferDirection =3D=3D SdTransferDirectionRead) { + if (BlockCount =3D=3D 1) { + Cmd =3D &CmdReadSingleBlock; + } else { + Cmd =3D &CmdReadMultiBlock; + } + } else { + if (BlockCount =3D=3D 1) { + Cmd =3D &CmdWriteSingleBlock; + } else { + Cmd =3D &CmdWriteMultiBlock; + } + } + + CONST UINT32 DataCommandRetryCount =3D 3; + CONST UINT32 MaxTransferSize =3D + HostInst->HostCapabilities.MaximumBlockCount * This->Media->BlockSize; + UINT32 Retry; + UINT32 BytesRemaining =3D BufferSize; + UINTN CurrentBufferSize; + VOID *CurrentBuffer =3D Buffer; + UINT32 CurrentLba =3D (UINT32) Lba; + + for (; BytesRemaining > 0;) { + if (BytesRemaining < MaxTransferSize) { + CurrentBufferSize =3D BytesRemaining; + } else { + CurrentBufferSize =3D MaxTransferSize; + } + + for (Retry =3D 0; Retry < DataCommandRetryCount; ++Retry) { + Status =3D SdhcSendDataCommand ( + HostInst, + Cmd, + CurrentLba, + CurrentBufferSize, + CurrentBuffer); + + if (!EFI_ERROR (Status)) { + if (Retry > 0) { + LOG_TRACE ("SdhcSendDataCommand succeeded after %d retry", Retry= ); + } + break; + } + + // On SdhcSendDataCommand return, proper error recovery has been per= formed + // and it should be safe to retry the same transfer. + + LOG_ERROR ("SdhcSendDataCommand failed on retry %d", Retry); + } + + BytesRemaining -=3D CurrentBufferSize; + CurrentLba +=3D CurrentBufferSize / This->Media->BlockSize; + CurrentBuffer =3D (VOID*) ((UINTN) CurrentBuffer + CurrentBufferSize); + } + +Exit: + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "IoBlocks(%c, LBA:0x%08lx, Size(B):0x%x): SdhcSendDataCommand() fail= ed. %r", + ((TransferDirection =3D=3D SdTransferDirectionRead) ? 'R' : 'W'), + Lba, + BufferSize, + Status); + } + + return Status; +} + +// EFI_BLOCK_IO Protocol Callbacks + +/** + Reset the block device. + + This function implements EFI_BLOCK_IO_PROTOCOL.Reset(). + It resets the block device hardware. + ExtendedVerification is ignored in this implementation. + + @param This Indicates a pointer to the calling contex= t. + @param ExtendedVerification Indicates that the driver may perform a m= ore exhaustive + verification operation of the device duri= ng reset. + + @retval EFI_SUCCESS The block device was reset. + @retval EFI_DEVICE_ERROR The block device is not functioning corre= ctly and could not be reset. + +**/ +EFI_STATUS +EFIAPI +BlockIoReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + LOG_TRACE ("BlockIoReset()"); + + SDHC_INSTANCE *HostInst =3D SDHC_INSTANCE_FROM_BLOCK_IO_THIS (This); + return SoftReset (HostInst); +} + +/** + Reads the requested number of blocks from the device. + + This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks(). + It reads the requested number of blocks from the device. + All the blocks are read, or an error is returned. + + @param This Indicates a pointer to the calling contex= t. + @param MediaId The media ID that the read request is for= . + @param Lba The starting logical block address to rea= d from on the device. + @param BufferSize The size of the Buffer in bytes. + This must be a multiple of the intrinsic = block size of the device. + @param Buffer A pointer to the destination buffer for t= he data. The caller is + responsible for either having implicit or= explicit ownership of the buffer. + + @retval EFI_SUCCESS The data was read correctly from the devi= ce. + @retval EFI_DEVICE_ERROR The device reported an error while attemp= ting to perform the read operation. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multipl= e of the intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are n= ot valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +BlockIoReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + LOG_TRACE ("BlockIoReadBlocks()"); + +#if SDMMC_BENCHMARK_IO + static BOOLEAN BenchmarkDone =3D FALSE; + if (!BenchmarkDone) { + + LOG_INFO ("Benchmarking BlockIo Read"); + + UINT32 CurrByteSize =3D 512; + CONST UINT32 MaxByteSize =3D 8388608; // 8MB Max + for (; CurrByteSize <=3D MaxByteSize; CurrByteSize *=3D 2) { + BenchmarkIo (This, SdTransferDirectionRead, MediaId, CurrByteSize, 1= 0); + } + + BenchmarkDone =3D TRUE; + } +#endif // SDMMC_BENCHMARK_IO + +#if SDMMC_COLLECT_STATISTICS + UINT32 NumBlocks =3D BufferSize / This->Media->BlockSize; + SDHC_INSTANCE *HostInst =3D SDHC_INSTANCE_FROM_BLOCK_IO_THIS (This); + CONST UINT32 TableSize =3D ARRAYSIZE (HostInst->IoReadStats); + IoReadStatsEntry *CurrentReadEntry =3D NULL; + + UINT32 BlockIdx; + for (BlockIdx =3D 0; BlockIdx < TableSize; ++BlockIdx) { + IoReadStatsEntry *Entry =3D HostInst->IoReadStats + BlockIdx; + // Reached end of table and didn't find a match, append an entry + if (Entry->NumBlocks =3D=3D 0) { + ++HostInst->IoReadStatsNumEntries; + Entry->NumBlocks =3D NumBlocks; + } + + if (Entry->NumBlocks =3D=3D NumBlocks) { + CurrentReadEntry =3D Entry; + ++Entry->Count; + break; + } + } + ASSERT (BlockIdx < TableSize); + + UINT64 StartTime =3D GetPerformanceCounter (); + + EFI_STATUS Status =3D IoBlocks ( + This, + SdTransferDirectionRead, + MediaId, + Lba, + BufferSize, + Buffer + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + UINT64 EndTime =3D GetPerformanceCounter (); + + ASSERT (CurrentReadEntry !=3D NULL); + CurrentReadEntry->TotalTransferTimeUs +=3D + (UINT32) (((EndTime - StartTime) * 1000000UL) / gHpcTicksPerSeconds); + + // + // Run statistics and dump updates + // + SortIoReadStatsByTotalTransferTime ( + HostInst->IoReadStats, + HostInst->IoReadStatsNumEntries); + + IoReadStatsEntry *MaxNumBlocksEntry =3D HostInst->IoReadStats; + IoReadStatsEntry *MaxCountEntry =3D HostInst->IoReadStats; + UINT32 TotalReadTimeUs =3D 0; + UINT32 TotalReadBlocksCount =3D 0; + + LOG_INFO (" #Blks\tCnt\tAvg(us)\tAll(us)"); + + for (BlockIdx =3D 0; BlockIdx < HostInst->IoReadStatsNumEntries; ++Block= Idx) { + IoReadStatsEntry *CurrEntry =3D HostInst->IoReadStats + BlockIdx; + + if (CurrEntry->NumBlocks > MaxNumBlocksEntry->NumBlocks) { + MaxNumBlocksEntry =3D CurrEntry; + } + + if (CurrEntry->Count > MaxCountEntry->Count) { + MaxCountEntry =3D CurrEntry; + } + + TotalReadTimeUs +=3D CurrEntry->TotalTransferTimeUs; + TotalReadBlocksCount +=3D (CurrEntry->NumBlocks * CurrEntry->Count); + + // Show only the top 5 time consuming transfers + if (BlockIdx < 5) { + LOG_INFO ( + " %d\t%d\t%d\t%d", + (UINT32) CurrEntry->NumBlocks, + (UINT32) CurrEntry->Count, + (UINT32) (CurrEntry->TotalTransferTimeUs / CurrEntry->Count), + (UINT32) CurrEntry->TotalTransferTimeUs); + } + } + + LOG_INFO ( + "MaxNumBlocksEntry: %d %d %dus", + (UINT32) MaxNumBlocksEntry->NumBlocks, + (UINT32) MaxNumBlocksEntry->Count, + (UINT32) MaxNumBlocksEntry->TotalTransferTimeUs); + + LOG_INFO ( + "MaxCountEntry: %d %d %dus", + (UINT32) MaxCountEntry->NumBlocks, + (UINT32) MaxCountEntry->Count, + (UINT32) MaxCountEntry->TotalTransferTimeUs); + + LOG_INFO ( + "UEFI spent %dus~%ds reading %dMB from SDCard\n", + TotalReadTimeUs, + INT_DIV_ROUND (TotalReadTimeUs, 1000000), + INT_DIV_ROUND (TotalReadBlocksCount * This->Media->BlockSize, (1024 * = 1024))); +Exit: + return Status; + +#else + return IoBlocks (This, SdTransferDirectionRead, MediaId, Lba, BufferSize= , Buffer); +#endif // SDMMC_COLLECT_STATISTICS +} + +/** + Writes a specified number of blocks to the device. + + This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks(). + It writes a specified number of blocks to the device. + All blocks are written, or an error is returned. + + @param This Indicates a pointer to the calling contex= t. + @param MediaId The media ID that the write request is fo= r. + @param Lba The starting logical block address to be = written. + @param BufferSize The size of the Buffer in bytes. + This must be a multiple of the intrinsic = block size of the device. + @param Buffer Pointer to the source buffer for the data= . + + @retval EFI_SUCCESS The data were written correctly to the de= vice. + @retval EFI_WRITE_PROTECTED The device cannot be written to. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_DEVICE_ERROR The device reported an error while attemp= ting to perform the write operation. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multipl= e of the intrinsic + block size of the device. + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are = not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +BlockIoWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + LOG_TRACE ("BlockIoWriteBlocks()"); + + return IoBlocks (This, SdTransferDirectionWrite, MediaId, Lba, BufferSiz= e, Buffer); +} + +/** + Flushes all modified data to a physical block device. + + @param This Indicates a pointer to the calling contex= t. + + @retval EFI_SUCCESS All outstanding data were written correct= ly to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attemp= ting to write data. + @retval EFI_NO_MEDIA There is no media in the device. + +**/ +EFI_STATUS +EFIAPI +BlockIoFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +{ + LOG_TRACE ("BlockIoFlushBlocks()"); + + return EFI_SUCCESS; +} diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/Debug.c b/Platform/Microso= ft/Drivers/SdMmcDxe/Debug.c new file mode 100644 index 000000000000..8fcef9f229ab --- /dev/null +++ b/Platform/Microsoft/Drivers/SdMmcDxe/Debug.c @@ -0,0 +1,358 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Copyright (c) 2011-2014, ARM Limited. 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 "SdMmcHw.h" +#include "SdMmc.h" +#include "Protocol.h" + +CONST CHAR8 *mStrUnit[] =3D { "100kbit/s", "1Mbit/s", "10Mbit/s", "100MBit= /s", + "Unknown", "Unknown", "Unknown", "Unknown" }; +CONST CHAR8 *mStrValue[] =3D { "UNDEF", "1.0", "1.2", "1.3", "1.5", "2.0",= "2.5", "3.0", "3.5", "4.0", "4.5", "5.0", + "Unknown", "Unknown", "Unknown", "Unknown" }; + +VOID +PrintCid ( + IN SDHC_INSTANCE *HostInst + ) +{ + LOG_INFO ("- PrintCid");; + + if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionSd) { + SD_CID *Cid =3D &HostInst->CardInfo.Registers.Sd.Cid; + LOG_INFO ("\t- Manufacturer ID: 0x%x", (UINT32) Cid->MID); + LOG_INFO ("\t- OEM ID: 0x%x", (UINT32) Cid->OID); + LOG_INFO ( + "\t- Product name: %c%c%c%c%c", + Cid->PNM[4], + Cid->PNM[3], + Cid->PNM[2], + Cid->PNM[1], + Cid->PNM[0]); + + LOG_INFO ( + "\t- Manufacturing date: %d/%d", + (UINT32) (Cid->MDT & 0xF), + (UINT32) (((Cid->MDT >> 4) & 0x3F) + 2000)); + LOG_INFO ("\t- Product serial number: 0x%X", Cid->PSN); + LOG_INFO ("\t- Product revision: %d", (UINT32) Cid->PRV); + + LOG_INFO ("\t- OEM ID: 0x%x", (UINT32) Cid->OID); + LOG_INFO ("\t- Manufacturer ID: 0x%x", (UINT32) Cid->MID); + } else { + MMC_CID *Cid =3D &HostInst->CardInfo.Registers.Mmc.Cid; + LOG_INFO ("\t- Manufacturer ID: 0x%x", (UINT32) Cid->MID); + LOG_INFO ("\t- OEM ID: 0x%x", (UINT32) Cid->OID); + LOG_INFO ( + "\t- Product name: %c%c%c%c%c%c\n", + Cid->PNM[5], + Cid->PNM[4], + Cid->PNM[3], + Cid->PNM[2], + Cid->PNM[1], + Cid->PNM[0]); + + LOG_INFO ( + "\t- Manufacturing date: %d/%d", + (UINT32) (Cid->MDT >> 4), + (UINT32) (Cid->MDT & 0xF) + 1997); + + LOG_INFO ("\t- Product serial number: 0x%X", Cid->PSN); + LOG_INFO ("\t- Product revision: %d", (UINT32) Cid->PRV); + } +} + +VOID +PrintCsd ( + IN SDHC_INSTANCE *HostInst + ) +{ + LOG_INFO ("- PrintCsd"); + + UINT32 CardSizeGB =3D + (UINT32) INT_DIV_ROUND (HostInst->CardInfo.ByteCapacity, (UINT64) (102= 4 * 1024 * 1024)); + + LOG_INFO ( + "\t- CardSize: %ld~%dGB, BlockSize:%d LastBlock LBA:0x%08x", + HostInst->CardInfo.ByteCapacity, + CardSizeGB, + HostInst->BlockIo.Media->BlockSize, + (UINT32) HostInst->BlockIo.Media->LastBlock); + + if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionSd) { + SD_CSD *Csd =3D &HostInst->CardInfo.Registers.Sd.Csd; + if (Csd->CSD_STRUCTURE =3D=3D 0) { + LOG_INFO ("- SD CSD Version 1.01-1.10/Version 2.00/Standard Capacity= "); + } else if (Csd->CSD_STRUCTURE =3D=3D 1) { + LOG_INFO ("- SD CSD Version 2.00/High Capacity"); + } else { + LOG_INFO ("- SD CSD Version Higher than v3.3"); + } + + LOG_INFO ( + "\t- SW Write Protect: Temp:%d Permanent:%d", + (UINT32) Csd->TMP_WRITE_PROTECT, + (UINT32) Csd->PERM_WRITE_PROTECT); + + LOG_INFO ("\t- Supported card command class: 0x%X", Csd->CCC); + + LOG_INFO ( + "\t- Speed: %a %a (TRAN_SPEED:%x)", + mStrValue[(Csd->TRAN_SPEED >> 3) & 0xF], + mStrUnit[Csd->TRAN_SPEED & 7], + (UINT32) Csd->TRAN_SPEED); + + LOG_INFO ( + "\t- Maximum Read Data Block: %d (READ_BL_LEN:%x)", + (UINT32) (1 << Csd->READ_BL_LEN), + (UINT32) Csd->READ_BL_LEN); + + LOG_INFO ( + "\t- Maximum Write Data Block: %d (WRITE_BL_LEN:%x)", + (UINT32) (1 << Csd->WRITE_BL_LEN), + (UINT32) Csd->WRITE_BL_LEN); + + if (!Csd->FILE_FORMAT_GRP) { + if (Csd->FILE_FORMAT =3D=3D 0) { + LOG_INFO ("\t- Format (0): Hard disk-like file system with partiti= on table"); + } else if (Csd->FILE_FORMAT =3D=3D 1) { + LOG_INFO ("\t- Format (1): DOS FAT (floppy-like) with boot sector = only (no partition table)"); + } else if (Csd->FILE_FORMAT =3D=3D 2) { + LOG_INFO ("\t- Format (2): Universal File Format"); + } else { + LOG_INFO ("\t- Format (3): Others/Unknown"); + } + } else { + LOG_INFO ("\t- Format: Reserved"); + } + } else { + MMC_CSD *Csd =3D &HostInst->CardInfo.Registers.Mmc.Csd; + MMC_EXT_CSD *ExtCsd =3D &HostInst->CardInfo.Registers.Mmc.ExtCsd; + + if (ExtCsd->CardType & MmcExtCsdCardTypeNormalSpeed) { + LOG_INFO ("\t- Normal-Speed MMC @ 26MHz"); + } + + if (ExtCsd->CardType & MmcExtCsdCardTypeHighSpeed) { + LOG_INFO ("\t- High-Speed MMC @ 52MHz"); + } + + if (ExtCsd->CardType & MmcExtCsdCardTypeDdr1v8) { + LOG_INFO ("\t- High-Speed DDR MMC @ 52MHz - 1.8V or 3V I/O"); + } + + if (ExtCsd->CardType & MmcExtCsdCardTypeDdr1v2) { + LOG_INFO ("\t- High-Speed DDR MMC @ 52MHz - 1.2VI/O"); + } + + LOG_INFO ( + "\t- SW Write Protect: Temp:%d Permenant:%d", + (UINT32) Csd->TMP_WRITE_PROTECT, + (UINT32) Csd->PERM_WRITE_PROTECT); + + LOG_INFO ("\t- SpecVersion: %d.x", (UINT32) Csd->SPEC_VERS); + LOG_INFO ("\t- Supported card command class: 0x%X", Csd->CCC); + + LOG_INFO ( + "\t- Current Max Speed: %a %a (TRAN_SPEED:%x)", + mStrValue[(Csd->TRAN_SPEED >> 3) & 0xF], + mStrUnit[Csd->TRAN_SPEED & 7], + (UINT32) Csd->TRAN_SPEED); + + LOG_INFO ( + "\t- Maximum Read Data Block: %d (READ_BL_LEN:%x)", + (UINT32) (1 << Csd->READ_BL_LEN), + (UINT32) Csd->READ_BL_LEN); + + LOG_INFO ( + "\t- Maximum Write Data Block: %d (WRITE_BL_LEN:%x)", + (UINT32) (1 << Csd->WRITE_BL_LEN), + (UINT32) Csd->WRITE_BL_LEN); + + if (!Csd->FILE_FORMAT_GRP) { + if (Csd->FILE_FORMAT =3D=3D 0) { + LOG_INFO ("\t- Format (0): Hard disk-like file system with partiti= on table"); + } else if (Csd->FILE_FORMAT =3D=3D 1) { + LOG_INFO ("\t- Format (1): DOS FAT (floppy-like) with boot sector = only (no partition table)"); + } else if (Csd->FILE_FORMAT =3D=3D 2) { + LOG_INFO ("\t- Format (2): Universal File Format"); + } else { + LOG_INFO ("\t- Format (3): Others/Unknown"); + } + } else { + LOG_INFO ("\t- Format: Reserved"); + } + } +} + +VOID +GetAndPrintCardStatus ( + IN SDHC_INSTANCE *HostInst + ) +{ + CARD_STATUS CardStatus; + EFI_STATUS Status; + + // + // If the card has not been selected, then we can't get its status + // + if (HostInst->CardInfo.RCA =3D=3D 0x0) { + return; + } + + Status =3D SdhcSendCommand (HostInst, &CmdSendStatus, 0); + if (EFI_ERROR (Status)) { + return; + } + + CardStatus.AsUint32 =3D HostInst->CmdResponse[0]; + PrintCardStatus (HostInst, CardStatus); +} + +VOID +PrintCardStatus ( + IN SDHC_INSTANCE *HostInst, + IN CARD_STATUS CardStatus + ) +{ + switch (HostInst->CardInfo.CardFunction) { + case CardFunctionSd: + LOG_INFO ( + "Status: APP_CMD:%d READY_FOR_DATA:%d CURRENT_STATE:%d(%a) " + "CARD_IS_LOCKED:%d", + CardStatus.Fields.APP_CMD, + CardStatus.Fields.READY_FOR_DATA, + CardStatus.Fields.CURRENT_STATE, + CardStateToString (CardStatus.Fields.CURRENT_STATE), + CardStatus.Fields.CARD_IS_LOCKED); + + break; + + case CardFunctionMmc: + LOG_INFO ( + "Status: APP_CMD:%d URGENT_BKOPS:%d READY_FOR_DATA:%d " + "CURRENT_STATE:%d(%a) CARD_IS_LOCKED:%d", + CardStatus.Fields.APP_CMD, + CardStatus.Fields.URGENT_BKOPS, + CardStatus.Fields.READY_FOR_DATA, + CardStatus.Fields.CURRENT_STATE, + CardStateToString (CardStatus.Fields.CURRENT_STATE), + CardStatus.Fields.CARD_IS_LOCKED); + + break; + + default: + ASSERT (FALSE); + } + + if (IsCardStatusError (HostInst, CardStatus)) { + LOG_INFO ("Errors:"); + + if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionSd) { + if (CardStatus.Fields.AKE_SEQ_ERROR) { + LOG_INFO ("\t- SWITCH_ERROR"); + } + } + + if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionMmc) { + if (CardStatus.Fields.SWITCH_ERROR) { + LOG_INFO ("\t- SWITCH_ERROR"); + } + + if (CardStatus.Fields.OVERRUN) { + LOG_INFO ("\t- OVERRUN"); + } + + if (CardStatus.Fields.UNDERRUN) { + LOG_INFO ("\t- UNDERRUN"); + } + } + + if (CardStatus.Fields.ERASE_RESET) { + LOG_INFO ("\t- ERASE_RESET"); + } + + if (CardStatus.Fields.WP_ERASE_SKIP) { + LOG_INFO ("\t- WP_ERASE_SKIP"); + } + + if (CardStatus.Fields.CID_CSD_OVERWRITE) { + LOG_INFO ("\t- CID_CSD_OVERWRITE"); + } + + if (CardStatus.Fields.ERROR) { + LOG_INFO ("\t- ERROR"); + } + + if (CardStatus.Fields.CC_ERROR) { + LOG_INFO ("\t- CC_ERROR"); + } + + if (CardStatus.Fields.CARD_ECC_FAILED) { + LOG_INFO ("\t- CARD_ECC_FAILED"); + } + + if (CardStatus.Fields.ILLEGAL_COMMAND) { + LOG_INFO ("\t- ILLEGAL_COMMAND"); + } + + if (CardStatus.Fields.COM_CRC_ERROR) { + LOG_INFO ("\t- COM_CRC_ERROR"); + } + + if (CardStatus.Fields.LOCK_UNLOCK_FAILED) { + LOG_INFO ("\t- LOCK_UNLOCK_FAILED"); + } + + if (CardStatus.Fields.WP_VIOLATION) { + LOG_INFO ("\t- WP_VIOLATION"); + } + + if (CardStatus.Fields.ERASE_PARAM) { + LOG_INFO ("\t- ERASE_PARAM"); + } + + if (CardStatus.Fields.ERASE_SEQ_ERROR) { + LOG_INFO ("\t- ERASE_SEQ_ERROR"); + } + + if (CardStatus.Fields.BLOCK_LEN_ERROR) { + LOG_INFO ("\t- BLOCK_LEN_ERROR"); + } + + if (CardStatus.Fields.ADDRESS_MISALIGN) { + LOG_INFO ("\t- ADDRESS_MISALIGN"); + } + + if (CardStatus.Fields.ADDRESS_OUT_OF_RANGE) { + LOG_INFO ("\t- ADDRESS_OUT_OF_RANGE"); + } + } +} diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/Protocol.c b/Platform/Micr= osoft/Drivers/SdMmcDxe/Protocol.c new file mode 100644 index 000000000000..d635fa6a1ef4 --- /dev/null +++ b/Platform/Microsoft/Drivers/SdMmcDxe/Protocol.c @@ -0,0 +1,1774 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Copyright (c) 2011-2014, ARM Limited. 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 "SdMmcHw.h" +#include "SdMmc.h" +#include "Protocol.h" + +EFI_STATUS +InitializeDevice ( + IN SDHC_INSTANCE *HostInst + ) +{ + LOG_TRACE ("InitializDevice()"); + ASSERT (!HostInst->SlotInitialized); + +#if SDMMC_BENCHMARK_IO + UINT64 InitializationStartTime =3D HpcTimerStart (); +#endif // SDMMC_BENCHMARK_IO + + EFI_SDHC_PROTOCOL *HostExt =3D HostInst->HostExt; + ASSERT (HostExt); + EFI_STATUS Status; + + ASSERT (HostInst->BlockIo.Media->MediaPresent); + + ZeroMem (&HostInst->CardInfo, sizeof (HostInst->CardInfo)); + // + // SD/MMC cards on reset start in default normal speed mode + // + HostInst->CardInfo.CurrentSpeedMode =3D CardSpeedModeNormalSpeed; + + Status =3D HostExt->SoftwareReset (HostExt, SdhcResetTypeAll); + if (EFI_ERROR (Status)) { + LOG_ERROR ("HostExt->SoftwareReset() failed. %r", Status); + return Status; + } + + Status =3D HostExt->SetClock (HostExt, SD_IDENT_MODE_CLOCK_FREQ_HZ); + if (EFI_ERROR (Status)) { + LOG_ERROR ("HostExt->SetClock() failed. %r", Status); + return Status; + } + + Status =3D SdhcQueryCardType (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcQueryCardType() failed. %r", Status); + return Status; + } + + switch (HostInst->CardInfo.CardFunction) { + case CardFunctionComboSdSdio: + LOG_ERROR ("Combo SD/SDIO function is not supported"); + return EFI_UNSUPPORTED; + case CardFunctionSdio: + LOG_ERROR ("SDIO function is not supported"); + return EFI_UNSUPPORTED; + case CardFunctionSd: + Status =3D InitializeSdDevice (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("InitializeSdDevice() failed. %r", Status); + return Status; + } + break; + case CardFunctionMmc: + Status =3D InitializeMmcDevice (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("InitializeMmcDevice() failed. %r", Status); + return Status; + } + break; + default: + LOG_ASSERT ("Unknown device function"); + return EFI_UNSUPPORTED; + } + + PrintCid (HostInst); + PrintCsd (HostInst); + + Status =3D SdhcSetBlockLength (HostInst, SD_BLOCK_LENGTH_BYTES); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSetBlockLength() failed. %r", Status); + return Status; + } + + ASSERT (HostInst->CardInfo.CardFunction =3D=3D CardFunctionSd || + HostInst->CardInfo.CardFunction =3D=3D CardFunctionMmc); + + if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionSd) { + HostInst->BlockIo.Media->RemovableMedia =3D TRUE; + HostInst->BlockIo.Media->MediaId =3D HostInst->CardInfo.Registers.Sd.C= id.PSN; + } else { + // + // Assume BGA form factor eMMC + // + HostInst->BlockIo.Media->RemovableMedia =3D FALSE; + + // + // Use the card product serial number as MediaId + // + HostInst->BlockIo.Media->MediaId =3D HostInst->CardInfo.Registers.Mmc.= Cid.PSN; + } + + HostInst->SlotInitialized =3D TRUE; + +#if SDMMC_BENCHMARK_IO + UINT64 ElapsedTimeMs =3D HpcTimerElapsedMilliseconds (InitializationStar= tTime); + LOG_INFO ("Initialization completed in %ldms", ElapsedTimeMs); +#endif // SDMMC_BENCHMARK_IO + + return EFI_SUCCESS; +} + +EFI_STATUS +InitializeSdDevice ( + IN SDHC_INSTANCE *HostInst + ) +{ + EFI_STATUS Status; + + Status =3D SdhcSendOpCondSd (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSendOpCondSd() failed. %r", Status); + return Status; + } + + Status =3D SdhcSendCidAll (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSendCidAll() failed. %r", Status); + return Status; + } + + Status =3D SdhcSendRelativeAddr (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSendRelativeAddr() failed. %r", Status); + return Status; + } + + Status =3D SdhcSendCid (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSendCid() failed. %r", Status); + return Status; + } + + Status =3D SdhcSendCsd (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSendCsd() failed. %r", Status); + return Status; + } + + Status =3D SdhcSelectDevice (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSelectDevice() failed. %r", Status); + return Status; + } + + Status =3D SdhcSwitchBusWidthSd (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSwitchBusWidthSd() failed. %r", Status); + return Status; + } + + Status =3D SdhcSwitchSpeedModeSd (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSwitchSpeedModeSd() failed. %r", Status); + return Status; + } + + Status =3D SdhcSetMaxClockFrequency (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSetMaxClockFrequency() failed. %r", Status); + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +InitializeMmcDevice ( + IN SDHC_INSTANCE *HostInst + ) +{ + EFI_STATUS Status; + + Status =3D SdhcSendCidAll (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSendCidAll() failed. %r", Status); + return Status; + } + + Status =3D SdhcSendRelativeAddr (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSendRelativeAddr() failed. %r", Status); + return Status; + } + + Status =3D SdhcSendCid (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSendCid() failed. %r", Status); + return Status; + } + + Status =3D SdhcSendCsd (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSendCsd() failed. %r", Status); + return Status; + } + + if (HostInst->CardInfo.Registers.Mmc.Csd.SPEC_VERS < MMC_MIN_SUPPORTED_S= PEC_VERS) { + LOG_ERROR ( + "MMC %d.x is not supported, Minimum supported is MMC %d.x", + HostInst->CardInfo.Registers.Mmc.Csd.SPEC_VERS, + MMC_MIN_SUPPORTED_SPEC_VERS); + return EFI_UNSUPPORTED; + } + + Status =3D SdhcSelectDevice (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSelectDevice() failed. %r", Status); + return Status; + } + + Status =3D SdhcSendExtCsdMmc (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSendExtCsdMmc() failed. %r", Status); + return Status; + } + + Status =3D SdhcSwitchSpeedModeMmc (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSwitchSpeedModeMmc() failed. %r", Status); + return Status; + } + + Status =3D SdhcSwitchBusWidthMmc (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSwitchBusWidthMmc() failed. %r", Status); + return Status; + } + + Status =3D SdhcSetMaxClockFrequency (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSetMaxClockFrequency() failed. %r", Status); + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SdhcRecoverFromErrors ( + IN SDHC_INSTANCE *HostInst, + IN CONST SD_COMMAND *Cmd + ) +{ + EFI_STATUS Status; + CARD_STATUS CardStatus; + EFI_SDHC_PROTOCOL *HostExt; + + LOG_TRACE ( + "*** %cCMD%d Error recovery sequence start ***", + (Cmd->Class =3D=3D SdCommandClassApp ? 'A' : ' '), + (UINT32) Cmd->Index); + + HostExt =3D HostInst->HostExt; + HostInst->ErrorRecoveryAttemptCount +=3D 1; + + if (HostInst->ErrorRecoveryAttemptCount > SDMMC_ERROR_RECOVERY_ATTEMPT_T= HRESHOLD) { + LOG_ERROR ("RecursiveErrorRecoveryCount exceeded the threshold. Error = is unrecoverable!"); + Status =3D EFI_PROTOCOL_ERROR; + goto Exit; + } + + GetAndPrintCardStatus (HostInst); + + LOG_TRACE ("Reseting CMD line ..."); + Status =3D HostExt->SoftwareReset (HostExt, SdhcResetTypeCmd); + if (EFI_ERROR (Status)) { + LOG_ERROR ("HostExt->SoftwareReset(SdhcResetTypeCmd) failed. %r", Stat= us); + } + + if (Cmd->TransferType !=3D SdTransferTypeNone && + Cmd->TransferType !=3D SdTransferTypeUndefined) { + + LOG_TRACE ("Reseting DAT line ..."); + Status =3D HostExt->SoftwareReset (HostExt, SdhcResetTypeData); + if (EFI_ERROR (Status)) { + LOG_ERROR ("HostExt->SoftwareReset(SdhcResetTypeData) failed. %r", S= tatus); + } + } + + if (EFI_ERROR (Status)) { + LOG_TRACE ("CMD and/or DATA normal error recovery failed, trying SDHC = soft-reset"); + Status =3D SoftReset (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("All trials to recover from errors failed. %r"); + goto Exit; + } + } + + if (CmdsAreEqual (Cmd, &CmdWriteMultiBlock) || + CmdsAreEqual (Cmd, &CmdReadMultiBlock)) { + + Status =3D SdhcSendStatus (HostInst, &CardStatus); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSendStatus() failed. (Status =3D %r)", Status); + goto Exit; + } + + if (CardStatus.Fields.CURRENT_STATE !=3D CardStateTran) { + LOG_TRACE ("Stopping transmission ..."); + Status =3D SdhcStopTransmission (HostInst); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // Multi read/write failure reason will be written in the STOP_TRANS= MISSION + // response as part of the card status error flags. + // + CardStatus.AsUint32 =3D HostInst->CmdResponse[0]; + PrintCardStatus (HostInst, CardStatus); + } + } + +Exit: + + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "*** %cCMD%d Error recovery sequence failed " + "(Status =3D %r, ErrorRecoveryAttemptCount =3D %d) ***", + (Cmd->Class =3D=3D SdCommandClassApp ? 'A' : ' '), + (UINT32) Cmd->Index, + Status, + HostInst->ErrorRecoveryAttemptCount); + + } else { + LOG_TRACE ( + "*** %cCMD%d Error recovery sequence completed successfully " + "(ErrorRecoveryAttemptCount =3D %d) ***", + (Cmd->Class =3D=3D SdCommandClassApp ? 'A' : ' '), + (UINT32) Cmd->Index, + HostInst->ErrorRecoveryAttemptCount); + } + + HostInst->ErrorRecoveryAttemptCount -=3D 1; + + return Status; +} + +EFI_STATUS +SdhcSendCommandHelper ( + IN SDHC_INSTANCE *HostInst, + IN CONST SD_COMMAND *Cmd, + IN UINT32 Arg, + IN SD_COMMAND_XFR_INFO *XfrInfo + ) +{ + EFI_SDHC_PROTOCOL *HostExt =3D HostInst->HostExt; + EFI_STATUS Status; + CARD_STATUS CardStatus; + + if (Cmd->Class =3D=3D SdCommandClassApp) { + UINT32 CmdAppArg =3D HostInst->CardInfo.RCA << 16; + Status =3D HostExt->SendCommand (HostExt, &CmdAppSd, CmdAppArg, NULL); + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "HostExt->SendCommand(%cCMD%d, 0x%08x) failed. %r", + (Cmd->Class =3D=3D SdCommandClassApp ? 'A' : ' '), + (UINT32) Cmd->Index, + CmdAppArg, + Status); + + return Status; + } + } + + Status =3D HostExt->SendCommand (HostExt, Cmd, Arg, XfrInfo); + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "HostExt->SendCommand(%cCMD%d, 0x%08x) failed. %r", + (Cmd->Class =3D=3D SdCommandClassApp ? 'A' : ' '), + (UINT32) Cmd->Index, + Arg, + Status); + + return Status; + } + + Status =3D HostExt->ReceiveResponse (HostExt, Cmd, HostInst->CmdResponse= ); + if (EFI_ERROR (Status)) { + LOG_ERROR ("HostExt->ReceiveResponse() failed. %r", Status); + return Status; + } + + if ((Cmd->ResponseType =3D=3D SdResponseTypeR1) || + (Cmd->ResponseType =3D=3D SdResponseTypeR1B)) { + + CardStatus.AsUint32 =3D HostInst->CmdResponse[0]; + + if (IsCardStatusError (HostInst, CardStatus)) { + LOG_ERROR ( + "%cCMD%d card status error detected", + (Cmd->Class =3D=3D SdCommandClassApp ? 'A' : ' '), + (UINT32) Cmd->Index); + + PrintCardStatus (HostInst, CardStatus); + + return EFI_DEVICE_ERROR; + } + } + + HostInst->PreLastSuccessfulCmd =3D HostInst->LastSuccessfulCmd; + HostInst->LastSuccessfulCmd =3D Cmd; + + return EFI_SUCCESS; +} + +EFI_STATUS +SdhcSendCommand ( + IN SDHC_INSTANCE *HostInst, + IN CONST SD_COMMAND *Cmd, + IN UINT32 Arg + ) +{ + EFI_STATUS Status; + + Status =3D SdhcSendCommandHelper (HostInst, Cmd, Arg, NULL); + if (EFI_ERROR (Status)) { + LOG_ERROR ("Send no-data command failed. %r", Status); + SdhcRecoverFromErrors (HostInst, Cmd); + return Status; + } + + // + // SWITCH command can change card state to prog, we should wait the card= to + // transfer back to tran state and rais the READY_FOR_DATA flag to make = sure + // that switch operation was completed successfully + // + if (CmdsAreEqual (Cmd, &CmdSwitchMmc) || + CmdsAreEqual (Cmd, &CmdSwitchSd)) { + Status =3D SdhcWaitForTranStateAndReadyForData (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "SdhcWaitForTranStateAndReadyForData() failed after successful " + "SWITCH command. (Status =3D %r)", + Status); + return Status; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SdhcSendDataCommand ( + IN SDHC_INSTANCE *HostInst, + IN CONST SD_COMMAND *Cmd, + IN UINT32 Arg, + IN UINT32 BufferByteSize, + IN VOID *Buffer + ) +{ + EFI_SDHC_PROTOCOL *HostExt =3D HostInst->HostExt; + SD_COMMAND_XFR_INFO XfrInfo; + EFI_STATUS Status; + + ASSERT (BufferByteSize % SD_BLOCK_LENGTH_BYTES =3D=3D 0); + XfrInfo.BlockCount =3D BufferByteSize / SD_BLOCK_LENGTH_BYTES; + XfrInfo.BlockSize =3D SD_BLOCK_LENGTH_BYTES; + XfrInfo.Buffer =3D Buffer; + + Status =3D SdhcSendCommandHelper (HostInst, Cmd, Arg, &XfrInfo); + if (EFI_ERROR (Status)) { + goto Exit; + } + + if (Cmd->TransferDirection =3D=3D SdTransferDirectionRead) { + Status =3D HostExt->ReadBlockData ( + HostExt, + BufferByteSize, + (UINT32*) Buffer); + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "HostExt->ReadBlockData(Size: 0x%xB) failed. %r", + BufferByteSize, + Status); + goto Exit; + } + } else { + ASSERT (Cmd->TransferDirection =3D=3D SdTransferDirectionWrite); + Status =3D HostExt->WriteBlockData ( + HostExt, + BufferByteSize, + (UINT32*) Buffer); + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "HostExt->WriteBlockData(Size: 0x%xB) failed. %r", + BufferByteSize, + Status); + goto Exit; + } + } + + // + // If this is an open-ended multi-block read/write then explicitly send + // STOP_TRANSMISSION. A multi-block read/write with pre-defined block co= unt + // will be preceeded with SET_BLOCK_COUNT. + // + if ((CmdsAreEqual (Cmd, &CmdWriteMultiBlock) || + CmdsAreEqual (Cmd, &CmdReadMultiBlock)) && + ((HostInst->LastSuccessfulCmd =3D=3D NULL) || + !CmdsAreEqual (HostInst->PreLastSuccessfulCmd, &CmdSetBlockCount))= ) { + + Status =3D SdhcStopTransmission (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcStopTransmission() failed. (Status =3D %r)", Status)= ; + goto Exit; + } + } + + Status =3D SdhcWaitForTranStateAndReadyForData (HostInst); + if (EFI_ERROR (Status)) { + goto Exit; + } + +Exit: + + if (EFI_ERROR (Status)) { + LOG_ERROR ("Send data command failed. %r", Status); + SdhcRecoverFromErrors (HostInst, Cmd); + } + + return Status; +} + +EFI_STATUS +SdhcGoIdleState ( + IN SDHC_INSTANCE *HostInst + ) +{ + return SdhcSendCommand (HostInst, &CmdGoIdleState, 0); +} + +EFI_STATUS +SdhcQueryCardType ( + IN SDHC_INSTANCE *HostInst + ) +{ + EFI_STATUS Status =3D SdhcGoIdleState (HostInst); + if (EFI_ERROR (Status)) { + return Status; + } + + HostInst->CardInfo.CardFunction =3D CardFunctionUnknown; + + Status =3D SdhcSendIfCondSd (HostInst); + if (!EFI_ERROR (Status)) { + HostInst->CardInfo.CardFunction =3D CardFunctionSd; + } + + Status =3D SdhcSendOpCondSdio (HostInst); + if (!EFI_ERROR (Status)) { + if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionSd) { + // + // SD/SDIO Combo Device + // + HostInst->CardInfo.CardFunction =3D CardFunctionComboSdSdio; + } else { + HostInst->CardInfo.CardFunction =3D CardFunctionSdio; + } + } + + if (HostInst->CardInfo.CardFunction !=3D CardFunctionSd && + HostInst->CardInfo.CardFunction !=3D CardFunctionSdio && + HostInst->CardInfo.CardFunction !=3D CardFunctionComboSdSdio) { + Status =3D SdhcGoIdleState (HostInst); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D SdhcSendOpCondMmc (HostInst); + if (!EFI_ERROR (Status)) { + HostInst->CardInfo.CardFunction =3D CardFunctionMmc; + } + } + + if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionUnknown) { + return EFI_NO_MEDIA; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SdhcWaitForTranStateAndReadyForData ( + IN SDHC_INSTANCE *HostInst + ) +{ + EFI_STATUS Status; + UINT32 Retry; + CARD_STATUS CardStatus; + + Status =3D SdhcSendStatus (HostInst, &CardStatus); + if (EFI_ERROR (Status)) { + return Status; + } + + Retry =3D SDMMC_POLL_WAIT_COUNT; + + while (((!CardStatus.Fields.READY_FOR_DATA && Retry) || + (CardStatus.Fields.CURRENT_STATE !=3D CardStateTran)) && + Retry) { + + gBS->Stall (SDMMC_POLL_WAIT_TIME_US); + --Retry; + + Status =3D SdhcSendStatus (HostInst, &CardStatus); + if (EFI_ERROR (Status)) { + return Status; + } + } + + if (!Retry) { + LOG_ERROR ("Time-out waiting for card READY_FOR_DATA status flag"); + PrintCardStatus (HostInst, CardStatus); + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SdhcSendCid ( + IN SDHC_INSTANCE *HostInst + ) +{ + UINT32 CmdArg =3D HostInst->CardInfo.RCA << 16; + + EFI_STATUS Status =3D SdhcSendCommand (HostInst, &CmdSendCid, CmdArg); + if (EFI_ERROR (Status)) { + return Status; + } + + if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionSd) { + gBS->CopyMem ( + (VOID*) &HostInst->CardInfo.Registers.Sd.Cid, + (VOID*) HostInst->CmdResponse, + sizeof (SD_CID)); + + } else if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionMmc) { + gBS->CopyMem ( + (VOID*) &HostInst->CardInfo.Registers.Mmc.Cid, + (VOID*) HostInst->CmdResponse, + sizeof (MMC_CID)); + + C_ASSERT (sizeof (HostInst->RpmbIo.Cid) =3D=3D EFI_RPMB_CID_SIZE); + gBS->CopyMem ( + (VOID*) &HostInst->RpmbIo.Cid, + (VOID*) HostInst->CmdResponse, + EFI_RPMB_CID_SIZE); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SdhcSendCsd ( + IN SDHC_INSTANCE *HostInst + ) +{ + UINT32 CmdArg =3D HostInst->CardInfo.RCA << 16; + + EFI_STATUS Status =3D SdhcSendCommand (HostInst, &CmdSendCsd, CmdArg); + if (EFI_ERROR (Status)) { + return Status; + } + + UINT32 MaxBlockLen; + UINT64 ByteCapacity =3D 0; + + if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionSd) { + gBS->CopyMem ( + (VOID*) &HostInst->CardInfo.Registers.Sd.Csd, + (VOID*) HostInst->CmdResponse, + sizeof (SD_CSD)); + if (HostInst->CardInfo.Registers.Sd.Csd.CSD_STRUCTURE =3D=3D 0) { + SD_CSD* Csd =3D (SD_CSD*) &HostInst->CardInfo.Registers.Sd.Csd; + UINT32 DeviceSize =3D ((Csd->C_SIZEHigh10 << 2) | Csd->C_SIZELow2); + UINT32 MULT =3D 1 << (Csd->C_SIZE_MULT + 2); + UINT32 BLOCKNR =3D (DeviceSize + 1) * MULT; + MaxBlockLen =3D 1 << Csd->READ_BL_LEN; + ByteCapacity =3D BLOCKNR * MaxBlockLen; + } else { + SD_CSD_2* Csd2 =3D (SD_CSD_2*) &HostInst->CardInfo.Registers.Sd.Csd; + MaxBlockLen =3D 1 << Csd2->READ_BL_LEN; + ByteCapacity =3D (UINT64) (Csd2->C_SIZE + 1) * 512llu * 1024llu; + } + } else if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionMmc) { + gBS->CopyMem ( + (VOID*) &HostInst->CardInfo.Registers.Mmc.Csd, + (VOID*) HostInst->CmdResponse, + sizeof (MMC_CSD)); + // + // HighCapacity MMC requires reading EXT_CSD to calculate capacity + // + if (!HostInst->CardInfo.HighCapacity) { + MMC_CSD* Csd =3D (MMC_CSD*) &HostInst->CardInfo.Registers.Mmc.Csd; + UINT32 DeviceSize =3D ((Csd->C_SIZEHigh10 << 2) | Csd->C_SIZELow2); + UINT32 MULT =3D 1 << (Csd->C_SIZE_MULT + 2); + UINT32 BLOCKNR =3D (DeviceSize + 1) * MULT; + MaxBlockLen =3D 1 << Csd->READ_BL_LEN; + ByteCapacity =3D BLOCKNR * MaxBlockLen; + } + } + + HostInst->CardInfo.ByteCapacity =3D ByteCapacity; + HostInst->BlockIo.Media->BlockSize =3D SD_BLOCK_LENGTH_BYTES; + UINT64 NumBlocks =3D (ByteCapacity / SD_BLOCK_LENGTH_BYTES); + + if (NumBlocks > 0) { + HostInst->BlockIo.Media->LastBlock =3D (NumBlocks - 1); + } else { + HostInst->BlockIo.Media->LastBlock =3D 0; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SdhcSelectDevice ( + IN SDHC_INSTANCE *HostInst + ) +{ + UINT32 CmdArg =3D HostInst->CardInfo.RCA << 16; + return SdhcSendCommand (HostInst, &CmdSelect, CmdArg); +} + +EFI_STATUS +SdhcDeselectDevice ( + IN SDHC_INSTANCE *HostInst + ) +{ + return SdhcSendCommand (HostInst, &CmdDeselect, 0); +} + +EFI_STATUS +SdhcSendAppCmd ( + IN SDHC_INSTANCE *HostInst + ) +{ + UINT32 CmdArg =3D HostInst->CardInfo.RCA << 16; + return SdhcSendCommand (HostInst, &CmdAppSd, CmdArg); +} + +EFI_STATUS +SdhcStopTransmission ( + IN SDHC_INSTANCE *HostInst + ) +{ + UINT32 CmdArg =3D HostInst->CardInfo.RCA << 16; + return SdhcSendCommand (HostInst, &CmdStopTransmission, CmdArg); +} + +EFI_STATUS +SdhcSendCidAll ( + IN SDHC_INSTANCE *HostInst + ) +{ + return SdhcSendCommand (HostInst, &CmdSendCidAll, 0); +} + +EFI_STATUS +SdhcSendRelativeAddr ( + IN SDHC_INSTANCE *HostInst + ) +{ + UINT32 CmdArg =3D 0; + + // + // Unlike SD memory, MMC cards don't publish their RCA, instead it shoul= d be + // manually assigned by the SDHC + // + if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionMmc) { + HostInst->CardInfo.RCA =3D 0xCCCC; + CmdArg =3D HostInst->CardInfo.RCA << 16; + } + + EFI_STATUS Status =3D SdhcSendCommand (HostInst, &CmdSendRelativeAddr, C= mdArg); + if (EFI_ERROR (Status)) { + return Status; + } + + if (HostInst->CardInfo.CardFunction !=3D CardFunctionMmc) { + HostInst->CardInfo.RCA =3D (HostInst->CmdResponse[0] >> 16); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +CalculateCardMaxFreq ( + IN SDHC_INSTANCE *HostInst, + OUT UINT32* MaxClkFreqHz + ) +{ + ASSERT (HostInst !=3D NULL); + ASSERT (MaxClkFreqHz !=3D NULL); + + SD_CSD *Csd =3D &HostInst->CardInfo.Registers.Sd.Csd; + UINT32 TransferRateBitPerSecond =3D 0; + UINT32 TimeValue =3D 0; + UINT32 TRAN_SPEED; + + if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionSd) { + TRAN_SPEED =3D HostInst->CardInfo.Registers.Sd.Csd.TRAN_SPEED; + } else { + TRAN_SPEED =3D HostInst->CardInfo.Registers.Mmc.Csd.TRAN_SPEED; + } + + // Calculate Transfer rate unit (Bits 2:0 of TRAN_SPEED) + switch (TRAN_SPEED & 0x7) { // 2 + case 0: // 100kbit/s + TransferRateBitPerSecond =3D 100 * 1000; + break; + + case 1: // 1Mbit/s + TransferRateBitPerSecond =3D 1 * 1000 * 1000; + break; + + case 2: // 10Mbit/s + TransferRateBitPerSecond =3D 10 * 1000 * 1000; + break; + + case 3: // 100Mbit/s + TransferRateBitPerSecond =3D 100 * 1000 * 1000; + break; + + default: + LOG_ERROR ("Invalid parameter"); + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + //Calculate Time value (Bits 6:3 of TRAN_SPEED) + switch ((TRAN_SPEED >> 3) & 0xF) { // 6 + case 0x1: + TimeValue =3D 10; + break; + + case 0x2: + TimeValue =3D 12; + break; + + case 0x3: + TimeValue =3D 13; + break; + + case 0x4: + TimeValue =3D 15; + break; + + case 0x5: + TimeValue =3D 20; + break; + + case 0x6: + if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionSd) { + TimeValue =3D 25; + } else { + TimeValue =3D 26; + } + break; + + case 0x7: + TimeValue =3D 30; + break; + + case 0x8: + TimeValue =3D 35; + break; + + case 0x9: + TimeValue =3D 40; + break; + + case 0xA: + TimeValue =3D 45; + break; + + case 0xB: + if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionSd) { + TimeValue =3D 50; + } else { + TimeValue =3D 52; + } + break; + + case 0xC: + TimeValue =3D 55; + break; + + case 0xD: + TimeValue =3D 60; + break; + + case 0xE: + TimeValue =3D 70; + break; + + case 0xF: + TimeValue =3D 80; + break; + + default: + LOG_ERROR ("Invalid parameter"); + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + *MaxClkFreqHz =3D (TransferRateBitPerSecond * TimeValue) / 10; + + LOG_TRACE ( + "TransferRateUnitId=3D%d TimeValue*10=3D%d, CardFrequency=3D%dKHz", + (Csd->TRAN_SPEED & 0x7), + TimeValue, + *MaxClkFreqHz / 1000); + + return EFI_SUCCESS; +} + +EFI_STATUS +SdhcSetMaxClockFrequency ( + IN SDHC_INSTANCE *HostInst + ) +{ + EFI_SDHC_PROTOCOL *HostExt =3D HostInst->HostExt; + EFI_STATUS Status; + UINT32 MaxClkFreqHz =3D 0; + + // + // Currently only NormalSpeed and HighSpeed supported + // + ASSERT (HostInst->CardInfo.CurrentSpeedMode =3D=3D CardSpeedModeNormalSp= eed || + HostInst->CardInfo.CurrentSpeedMode =3D=3D CardSpeedModeHighSpee= d); + + if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionSd) { + Status =3D CalculateCardMaxFreq (HostInst, &MaxClkFreqHz); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + if (HostInst->CardInfo.CurrentSpeedMode =3D=3D CardSpeedModeNormalSpee= d) { + Status =3D CalculateCardMaxFreq (HostInst, &MaxClkFreqHz); + if (EFI_ERROR (Status)) { + return Status; + } + } else if (HostInst->CardInfo.CurrentSpeedMode =3D=3D CardSpeedModeHig= hSpeed) { + MaxClkFreqHz =3D MMC_HIGH_SPEED_MODE_CLOCK_FREQ_HZ; + } + } + + Status =3D HostExt->SetClock (HostExt, MaxClkFreqHz); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SdhcSetBlockLength ( + IN SDHC_INSTANCE *HostInst, + IN UINT32 BlockByteLength + ) +{ + LOG_TRACE ("SdhcSetBlockLength(BlockByteLength=3D%d)", BlockByteLength); + + return SdhcSendCommand (HostInst, &CmdSetBlockLength, BlockByteLength); +} + +EFI_STATUS +SdhcSetBlockCount ( + IN SDHC_INSTANCE *HostInst, + IN UINT32 BlockCount, + IN BOOLEAN ReliableWrite + ) +{ + UINT32 CmdArg; + + LOG_TRACE ( + "SdhcSetBlockCount(BlockCount=3D%d, ReliableWrite=3D%d)", + BlockCount, + ReliableWrite); + + // + // JEDEC Standard No. 84-A441, Page 76 + // + // Set bit[31] as 1 to indicate Reliable Write type of programming acces= s. + // + + if (ReliableWrite) { + CmdArg =3D BlockCount | (1 << 31); + } else { + CmdArg =3D BlockCount; + } + + return SdhcSendCommand (HostInst, &CmdSetBlockCount, CmdArg); +} + +EFI_STATUS +SdhcSendStatus ( + IN SDHC_INSTANCE *HostInst, + OUT CARD_STATUS *CardStatus + ) +{ + EFI_STATUS Status; + UINT32 CmdArg; + + LOG_TRACE ("SdhcSendStatus()"); + + CmdArg =3D HostInst->CardInfo.RCA << 16; + + Status =3D SdhcSendCommand (HostInst, &CmdSendStatus, CmdArg); + if (EFI_ERROR (Status)) { + return Status; + } + + CardStatus->AsUint32 =3D HostInst->CmdResponse[0]; + + return EFI_SUCCESS; +} + +// +// SD Specific Functions +// + +EFI_STATUS +SdhcSendScrSd ( + IN SDHC_INSTANCE *HostInst + ) +{ + UINT32 CmdArg =3D HostInst->CardInfo.RCA << 16; + EFI_STATUS Status; + + Status =3D SdhcSendDataCommand ( + HostInst, + &CmdAppSendScrSd, + CmdArg, + sizeof (HostInst->BlockBuffer), + HostInst->BlockBuffer); + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CopyMem ( + &HostInst->CardInfo.Registers.Sd.Scr, + HostInst->BlockBuffer, + sizeof (SD_SCR)); + + SD_SCR *Scr =3D (SD_SCR*) &HostInst->BlockBuffer; + LOG_TRACE ("SD_SCR:"); + LOG_TRACE (" SD_SPEC=3D%d", (UINT32) Scr->SD_SPEC); + LOG_TRACE (" SD_SPEC3=3D%d", (UINT32) Scr->SD_SPEC3); + LOG_TRACE ( + " SD_BUS_WIDTHS=3D%x, 1-Bit?%d, 4-Bit?%d", + (UINT32) Scr->SD_BUS_WIDTH, + (UINT32) ((Scr->SD_BUS_WIDTH & BIT1) ? 1 : 0), + (UINT32) ((Scr->SD_BUS_WIDTH & BIT2) ? 1 : 0)); + LOG_TRACE ( + " CMD_SUPPORT=3D%x, CMD23?%d, CMD20?%d", + (UINT32) Scr->CMD_SUPPORT, + (UINT32) ((Scr->CMD_SUPPORT & BIT2) ? 1 : 0), + (UINT32) ((Scr->CMD_SUPPORT & BIT1) ? 1 : 0)); + + return EFI_SUCCESS; +} + +EFI_STATUS +SdhcSendIfCondSd ( + IN SDHC_INSTANCE *HostInst + ) +{ + SEND_IF_COND_ARG CmdArg =3D { 0 }; + + // + // Recommended check pattern per SD Specs + // + CmdArg.Fields.CheckPattern =3D 0xAA; + + // + // Our current implementation does not support more than HighSpeed volta= ge 2V7-3V6 (i.e no 1V8) + // + CmdArg.Fields.VoltageSupplied =3D SD_CMD8_VOLTAGE_27_36; + + EFI_STATUS Status =3D SdhcSendCommand (HostInst, &CmdSendIfCondSd, CmdAr= g.AsUint32); + if (EFI_ERROR (Status)) { + return Status; + } + + SEND_IF_COND_CMD_RESPONSE CmdStatus; + CmdStatus.AsUint32 =3D HostInst->CmdResponse[0]; + + if (CmdStatus.Fields.CheckPattern !=3D CmdArg.Fields.CheckPattern || + CmdStatus.Fields.VoltageSupplied !=3D CmdArg.Fields.VoltageSupplied)= { + return EFI_UNSUPPORTED; + } + + HostInst->CardInfo.HasExtendedOcr =3D TRUE; + + return EFI_SUCCESS;; +} + +EFI_STATUS +SdhcSendOpCondSd ( + IN SDHC_INSTANCE *HostInst + ) +{ + EFI_STATUS Status; + + // + // With arg set to 0, it means read OCR + // + Status =3D SdhcSendCommand (HostInst, &CmdAppSendOpCondSd, 0); + if (EFI_ERROR (Status)) { + return Status; + } + + HostInst->CardInfo.Registers.Sd.Ocr.AsUint32 =3D HostInst->CmdResponse[0= ]; + + SD_SEND_OP_COND_ARG CmdArg =3D { 0 }; + UINT32 Retry =3D SDMMC_POLL_WAIT_COUNT; + SD_OCR Ocr; + SD_OCR_EX *OcrEx; + + CmdArg.Fields.VoltageWindow =3D HostInst->CardInfo.Registers.Sd.Ocr.Fiel= ds.VoltageWindow; + // + // Host support for High Capacity is assumed + // + CmdArg.Fields.HCS =3D 1; + + while (Retry) { + Status =3D SdhcSendCommand (HostInst, &CmdAppSendOpCondSd, CmdArg.AsUi= nt32); + if (EFI_ERROR (Status)) { + return Status; + } + + Ocr.AsUint32 =3D HostInst->CmdResponse[0]; + + if (Ocr.Fields.PowerUp) { + LOG_TRACE ("SD Card PowerUp Complete"); + if (HostInst->CardInfo.HasExtendedOcr) { + OcrEx =3D (SD_OCR_EX*) &Ocr; + if (OcrEx->Fields.CCS) { + LOG_TRACE ("Card is SD2.0 or later HighCapacity SDHC or SDXC"); + HostInst->CardInfo.HighCapacity =3D TRUE; + } else { + LOG_TRACE ("Card is SD2.0 or later StandardCapacity SDSC"); + HostInst->CardInfo.HighCapacity =3D FALSE; + } + } + break; + } + gBS->Stall (SDMMC_POLL_WAIT_TIME_US); + --Retry; + } + + if (!Retry) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +SdhcSwitchBusWidthSd ( + IN SDHC_INSTANCE *HostInst + ) +{ + EFI_SDHC_PROTOCOL *HostExt =3D HostInst->HostExt; + EFI_STATUS Status; + UINT32 CmdArg; + + //Status =3D SdhcSendScrSd(HostInst); + //if (EFI_ERROR(Status)) { + // return Status; + //} + + CmdArg =3D 0x2; // 4-bit + Status =3D SdhcSendCommand (HostInst, &CmdAppSetBusWidthSd, CmdArg); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D HostExt->SetBusWidth (HostExt, SdBusWidth4Bit); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SdhcSwitchSpeedModeSd ( + IN SDHC_INSTANCE *HostInst + ) +{ + return EFI_SUCCESS; +} + +// +// SDIO Specific Functions +// + +EFI_STATUS +SdhcSendOpCondSdio ( + IN SDHC_INSTANCE *HostInst + ) +{ + return SdhcSendCommand (HostInst, &CmdSendOpCondSdio, 0); +} + +// +// Mmc Specific Functions +// + +EFI_STATUS +SdhcSendOpCondMmc ( + IN SDHC_INSTANCE *HostInst + ) +{ + EFI_STATUS Status; + MMC_SEND_OP_COND_ARG CmdArg =3D { 0 }; + UINT32 Retry =3D SDMMC_POLL_WAIT_COUNT; + MMC_OCR *Ocr =3D &HostInst->CardInfo.Registers.Mmc.Ocr; + + CmdArg.Fields.VoltageWindow =3D SD_OCR_HIGH_VOLTAGE_WINDOW; + CmdArg.Fields.AccessMode =3D SdOcrAccessSectorMode; + + while (Retry) { + Status =3D SdhcSendCommand (HostInst, &CmdSendOpCondMmc, CmdArg.AsUint= 32); + if (EFI_ERROR (Status)) { + return Status; + } + + HostInst->CardInfo.Registers.Mmc.Ocr.AsUint32 =3D HostInst->CmdRespons= e[0]; + + if (Ocr->Fields.PowerUp) { + LOG_TRACE ("MMC Card PowerUp Complete"); + if (Ocr->Fields.AccessMode =3D=3D SdOcrAccessSectorMode) { + LOG_TRACE ("Card is MMC HighCapacity"); + HostInst->CardInfo.HighCapacity =3D TRUE; + } else { + LOG_TRACE ("Card is MMC StandardCapacity"); + HostInst->CardInfo.HighCapacity =3D FALSE; + } + + if ((Ocr->Fields.VoltageWindow & SD_OCR_HIGH_VOLTAGE_WINDOW) !=3D SD= _OCR_HIGH_VOLTAGE_WINDOW) { + LOG_ERROR ( + "MMC Card does not support High Voltage, expected profile:%x act= ual profile:%x", + (UINT32) SD_OCR_HIGH_VOLTAGE_WINDOW, + (UINT32) Ocr->Fields.VoltageWindow); + return EFI_UNSUPPORTED; + } + + break; + } + gBS->Stall (SDMMC_POLL_WAIT_TIME_US); + --Retry; + } + + if (!Retry) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SdhcSwitchBusWidthMmc ( + IN SDHC_INSTANCE *HostInst + ) +{ + EFI_SDHC_PROTOCOL *HostExt =3D HostInst->HostExt; + EFI_STATUS Status; + UINT32 CmdArg; + SD_BUS_WIDTH BusWidth =3D SdBusWidth8Bit; + MMC_EXT_CSD *ExtCsd =3D &HostInst->CardInfo.Registers.Mmc.ExtCsd; + UINT8 ExtCsdPowerClass; + MMC_SWITCH_CMD_ARG SwitchCmdArg; + + Status =3D SdhcSendExtCsdMmc (HostInst); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Figure out current requirements for target bus width. An inrease in c= urrent consumption + // may require switching the card to a higher power class + // + if (BusWidth =3D=3D SdBusWidth8Bit) { + if (HostInst->CardInfo.CurrentSpeedMode =3D=3D CardSpeedModeHighSpeed)= { + ExtCsdPowerClass =3D MMC_EXT_CSD_POWER_CLASS_8BIT (ExtCsd->PowerClas= s52Mhz36V); + } else { + ExtCsdPowerClass =3D MMC_EXT_CSD_POWER_CLASS_8BIT (ExtCsd->PowerClas= s26Mhz36V); + } + } else if (BusWidth =3D=3D SdBusWidth4Bit) { + if (HostInst->CardInfo.CurrentSpeedMode =3D=3D CardSpeedModeHighSpeed)= { + ExtCsdPowerClass =3D MMC_EXT_CSD_POWER_CLASS_4BIT (ExtCsd->PowerClas= s52Mhz36V); + } else { + ExtCsdPowerClass =3D MMC_EXT_CSD_POWER_CLASS_4BIT (ExtCsd->PowerClas= s26Mhz36V); + } + } else { + return EFI_UNSUPPORTED; + } + + // + // Only do power class switch if the target bus width requires more curr= ent than the + // allowed by the current power class in EXT_CSD + // + if (ExtCsdPowerClass > HostInst->CardInfo.Registers.Mmc.ExtCsd.PowerClas= s) { + CmdArg =3D ExtCsdPowerClass; + CmdArg <<=3D 8; + CmdArg |=3D 0x03BB0000; + Status =3D SdhcSendCommand ( + HostInst, + &CmdSwitchMmc, + CmdArg); + if (EFI_ERROR (Status)) { + LOG_ERROR ("Error detected on switching PowerClass function"); + return Status; + } + + Status =3D SdhcSendExtCsdMmc (HostInst); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Sanity check that wanted power-class are set per requested + // + if (HostInst->CardInfo.Registers.Mmc.ExtCsd.PowerClass !=3D ExtCsdPowe= rClass) { + LOG_ERROR ( + "MMC EXT_CSD not reporting correct PowerClass after switch. Expect= ed:%x Actual:%x", + (UINT32) ExtCsdPowerClass, + (UINT32) HostInst->CardInfo.Registers.Mmc.ExtCsd.PowerClass); + return EFI_PROTOCOL_ERROR; + } + } + + // + // Switch bus width + // + SwitchCmdArg.AsUint32 =3D 0; + SwitchCmdArg.Fields.Access =3D MmcSwitchCmdAccessTypeWriteByte; + SwitchCmdArg.Fields.Index =3D MmcExtCsdBitIndexBusWidth; + + if (BusWidth =3D=3D SdBusWidth8Bit) { + SwitchCmdArg.Fields.Value =3D MmcExtCsdBusWidth8Bit; + } else { + SwitchCmdArg.Fields.Value =3D MmcExtCsdBusWidth4Bit; + } + + Status =3D SdhcSendCommand ( + HostInst, + &CmdSwitchMmc, + SwitchCmdArg.AsUint32); + if (EFI_ERROR (Status)) { + LOG_ERROR ("Error detected on switching BusWidth function"); + return Status; + } + + Status =3D HostExt->SetBusWidth (HostExt, BusWidth); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SdhcSwitchSpeedModeMmc ( + IN SDHC_INSTANCE *HostInst + ) +{ + EFI_STATUS Status; + MMC_SWITCH_CMD_ARG CmdArg; + + CmdArg.AsUint32 =3D 0; + CmdArg.Fields.Access =3D MmcSwitchCmdAccessTypeWriteByte; + CmdArg.Fields.Index =3D MmcExtCsdBitIndexHsTiming; + CmdArg.Fields.Value =3D 1; + + Status =3D SdhcSendCommand ( + HostInst, + &CmdSwitchMmc, + CmdArg.AsUint32); + if (EFI_ERROR (Status)) { + LOG_ERROR ("Error detected on switching HighSpeed function"); + return Status; + } + + HostInst->CardInfo.CurrentSpeedMode =3D CardSpeedModeHighSpeed; + + Status =3D SdhcSendExtCsdMmc (HostInst); + if (EFI_ERROR (Status)) { + return Status; + } + + if (!HostInst->CardInfo.Registers.Mmc.ExtCsd.HighSpeedTiming) { + LOG_ERROR ("MMC EXT_CSD not reporting HighSpeed timing after switch"); + return EFI_PROTOCOL_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SdhcSendExtCsdMmc ( + IN SDHC_INSTANCE *HostInst + ) +{ + EFI_STATUS Status; + UINT32 CmdArg; + MMC_EXT_CSD *ExtCsd; + + CmdArg =3D HostInst->CardInfo.RCA << 16; + ExtCsd =3D &HostInst->CardInfo.Registers.Mmc.ExtCsd; + + Status =3D SdhcSendDataCommand ( + HostInst, + &CmdSendExtCsdMmc, + CmdArg, + sizeof (HostInst->BlockBuffer), + HostInst->BlockBuffer); + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CopyMem (ExtCsd, HostInst->BlockBuffer, sizeof (MMC_EXT_CSD)); + + HostInst->CardInfo.ByteCapacity =3D (UINT64) ExtCsd->SectorCount * 512ll= u; + HostInst->BlockIo.Media->LastBlock =3D ExtCsd->SectorCount - 1; + + HostInst->RpmbIo.ReliableSectorCount =3D ExtCsd->ReliableWriteSectorCoun= t; + HostInst->RpmbIo.RpmbSizeMult =3D ExtCsd->RpmbSizeMult; + + return EFI_SUCCESS; +} + +EFI_STATUS +SdhcSwitchPartitionMmc ( + IN SDHC_INSTANCE *HostInst, + IN MMC_EXT_CSD_PARTITION_ACCESS Partition + ) +{ + EFI_STATUS Status; + MMC_SWITCH_CMD_ARG CmdArg; + MMC_EXT_CSD_PARTITION_CONFIG PartConfig; + + LOG_TRACE ( + "SdhcSwitchPartitionMmc(Partition=3D%a)", + MmcPartitionAccessToString (Partition)); + + PartConfig.AsUint8 =3D HostInst->CardInfo.Registers.Mmc.ExtCsd.Partition= Config; + PartConfig.Fields.PARTITION_ACCESS =3D Partition; + + // + // Write the partition type to EXT_CSD[PARTITION_CONFIG].PARTITION_ACCES= S + // + + ZeroMem (&CmdArg, sizeof (MMC_SWITCH_CMD_ARG)); + CmdArg.Fields.Access =3D MmcSwitchCmdAccessTypeWriteByte; + CmdArg.Fields.Index =3D MmcExtCsdBitIndexPartitionConfig; + CmdArg.Fields.Value =3D PartConfig.AsUint8; + + Status =3D SdhcSendCommand (HostInst, &CmdSwitchMmc, CmdArg.AsUint32); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSendCommand failed. (Status =3D %r)"); + return Status; + } + + // + // Re-read the EXT_CSD to verify the partition switch physically happenn= ed + // + Status =3D SdhcSendExtCsdMmc (HostInst); + if (EFI_ERROR (Status)) { + return Status; + } + + PartConfig.AsUint8 =3D HostInst->CardInfo.Registers.Mmc.ExtCsd.Partition= Config; + if (PartConfig.Fields.PARTITION_ACCESS !=3D Partition) { + LOG_ERROR ( + "Current partition indicated by EXT_CSD doesn't match the " + "partition the MMC should have switched to. Expected:%a Actual:%a", + MmcPartitionAccessToString (Partition), + MmcPartitionAccessToString (PartConfig.Fields.PARTITION_ACCESS)); + + return EFI_DEVICE_ERROR; + } + + LOG_TRACE ( + "Switched from partition %a to %a successfully", + MmcPartitionAccessToString (HostInst->CurrentMmcPartition), + MmcPartitionAccessToString (Partition)); + + HostInst->CurrentMmcPartition =3D Partition; + + return EFI_SUCCESS; +} + +// +// SD command definitions +// + +CONST SD_COMMAND CmdGoIdleState =3D +{ 0, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeNone, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdSendOpCondMmc =3D +{ 1, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR3, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdSendCidAll =3D +{ 2, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR2, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdSendRelativeAddr =3D +{ 3, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR6, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdSendOpCondSdio =3D +{ 5, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR4, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdSwitchSd =3D +{ 6, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR1, + SdTransferTypeSingleBlock, + SdTransferDirectionRead }; + +CONST SD_COMMAND CmdSwitchMmc =3D +{ 6, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR1B, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdAppSetBusWidthSd =3D +{ 6, + SdCommandTypeUndefined, + SdCommandClassApp, + SdResponseTypeR1, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdSelect =3D +{ 7, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR1B, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdDeselect =3D +{ 7, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeNone, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdSendIfCondSd =3D +{ 8, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR6, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdSendExtCsdMmc =3D +{ 8, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR1, + SdTransferTypeSingleBlock, + SdTransferDirectionRead }; + +CONST SD_COMMAND CmdSendCsd =3D +{ 9, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR2, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdSendCid =3D +{ 10, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR2, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdSwitchVoltageSd =3D +{ 11, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR1, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdStopTransmission =3D +{ 12, + SdCommandTypeAbort, + SdCommandClassStandard, + SdResponseTypeR1B, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdSendStatus =3D +{ 13, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR1, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdBusTestReadMmc =3D +{ 14, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR1, + SdTransferTypeSingleBlock, + SdTransferDirectionRead }; + +CONST SD_COMMAND CmdSetBlockLength =3D +{ 16, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR1, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdReadSingleBlock =3D +{ 17, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR1, + SdTransferTypeSingleBlock, + SdTransferDirectionRead }; + +CONST SD_COMMAND CmdReadMultiBlock =3D +{ 18, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR1, + SdTransferTypeMultiBlock, + SdTransferDirectionRead }; + +CONST SD_COMMAND CmdBusTestWriteMmc =3D +{ 19, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR1, + SdTransferTypeSingleBlock, + SdTransferDirectionWrite }; + +CONST SD_COMMAND CmdSetBlockCount =3D +{ 23, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR1, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdWriteSingleBlock =3D +{ 24, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR1, + SdTransferTypeSingleBlock, + SdTransferDirectionWrite }; + +CONST SD_COMMAND CmdWriteMultiBlock =3D +{ 25, + SdCommandTypeUndefined, + SdCommandClassStandard, + SdResponseTypeR1, + SdTransferTypeMultiBlock, + SdTransferDirectionWrite }; + +CONST SD_COMMAND CmdAppSendOpCondSd =3D +{ 41, + SdCommandTypeUndefined, + SdCommandClassApp, + SdResponseTypeR3, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdAppSetClrCardDetectSd =3D +{ 42, + SdCommandTypeUndefined, + SdCommandClassApp, + SdResponseTypeR1, + SdTransferTypeNone, + SdTransferDirectionUndefined }; + +CONST SD_COMMAND CmdAppSendScrSd =3D +{ 51, + SdCommandTypeUndefined, + SdCommandClassApp, + SdResponseTypeR1, + SdTransferTypeSingleBlock, + SdTransferDirectionRead }; + +CONST SD_COMMAND CmdAppSd =3D +{ 55, + SdCommandTypeUndefined, + SdCommandClassApp, + SdResponseTypeR1, + SdTransferTypeNone, + SdTransferDirectionUndefined }; diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/Protocol.h b/Platform/Micr= osoft/Drivers/SdMmcDxe/Protocol.h new file mode 100644 index 000000000000..24cb9909373b --- /dev/null +++ b/Platform/Microsoft/Drivers/SdMmcDxe/Protocol.h @@ -0,0 +1,231 @@ +/** @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 __PROTOCOL_H__ +#define __PROTOCOL_H__ + +EFI_STATUS +InitializeDevice ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +InitializeSdDevice ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +InitializeMmcDevice ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcSendCommand ( + IN SDHC_INSTANCE *HostInst, + IN CONST SD_COMMAND *Cmd, + IN UINT32 Arg + ); + +EFI_STATUS +SdhcSendDataCommand ( + IN SDHC_INSTANCE *HostInst, + IN CONST SD_COMMAND *Cmd, + IN UINT32 Arg, + IN UINT32 BufferByteSize, + IN OUT VOID *Buffer + ); + +// SD/SDIO/MMC Generic Functions + +EFI_STATUS +SdhcRecoverFromErrors ( + IN SDHC_INSTANCE *HostInst, + IN CONST SD_COMMAND *Cmd + ); + +EFI_STATUS +SdhcQueryCardType ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcGoIdleState ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcSendCidAll ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcSendRelativeAddr ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcWaitForTranStateAndReadyForData ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcSendCid ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcSendCsd ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcSendAppCmd ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcSelectDevice ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcDeselectDevice ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcStopTransmission ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcSetMaxClockFrequency ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcSetBlockLength ( + IN SDHC_INSTANCE *HostInst, + IN UINT32 BlockByteLength + ); + +EFI_STATUS +SdhcSetBlockCount ( + IN SDHC_INSTANCE *HostInst, + IN UINT32 BlockCount, + IN BOOLEAN ReliableWrite + ); + +EFI_STATUS +SdhcSendStatus ( + IN SDHC_INSTANCE *HostInst, + OUT CARD_STATUS *CardStatus + ); + +// SD Specific Functions + +EFI_STATUS +SdhcSendScrSd ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcSendOpCondSd ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcSendIfCondSd ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcSwitchBusWidthSd ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcSwitchSpeedModeSd ( + IN SDHC_INSTANCE *HostInst + ); + +// SDIO Specific Functions + +EFI_STATUS +SdhcSendOpCondSdio ( + IN SDHC_INSTANCE *HostInst + ); + +// MMC Specific Functions + +EFI_STATUS +SdhcSendOpCondMmc ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcSwitchBusWidthMmc ( + IN SDHC_INSTANCE *HostInst + ); + + +EFI_STATUS +SdhcSwitchSpeedModeMmc ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcSendExtCsdMmc ( + IN SDHC_INSTANCE *HostInst + ); + +EFI_STATUS +SdhcSwitchPartitionMmc ( + IN SDHC_INSTANCE *HostInst, + IN MMC_EXT_CSD_PARTITION_ACCESS Partition + ); + +// SD/MMC Commands + +extern CONST SD_COMMAND CmdGoIdleState; +extern CONST SD_COMMAND CmdSendOpCondMmc; +extern CONST SD_COMMAND CmdSendCidAll; +extern CONST SD_COMMAND CmdSendRelativeAddr; +extern CONST SD_COMMAND CmdSendOpCondSdio; +extern CONST SD_COMMAND CmdSwitchSd; +extern CONST SD_COMMAND CmdSwitchMmc; +extern CONST SD_COMMAND CmdAppSetBusWidthSd; +extern CONST SD_COMMAND CmdSelect; +extern CONST SD_COMMAND CmdDeselect; +extern CONST SD_COMMAND CmdSendIfCondSd; +extern CONST SD_COMMAND CmdSendExtCsdMmc; +extern CONST SD_COMMAND CmdSendCsd; +extern CONST SD_COMMAND CmdSendCid; +extern CONST SD_COMMAND CmdSwitchVoltageSd; +extern CONST SD_COMMAND CmdStopTransmission; +extern CONST SD_COMMAND CmdSendStatus; +extern CONST SD_COMMAND CmdBusTestReadMmc; +extern CONST SD_COMMAND CmdSetBlockLength; +extern CONST SD_COMMAND CmdReadSingleBlock; +extern CONST SD_COMMAND CmdReadMultiBlock; +extern CONST SD_COMMAND CmdBusTestWriteMmc; +extern CONST SD_COMMAND CmdSetBlockCount; +extern CONST SD_COMMAND CmdWriteSingleBlock; +extern CONST SD_COMMAND CmdWriteMultiBlock; +extern CONST SD_COMMAND CmdAppSendOpCondSd; +extern CONST SD_COMMAND CmdAppSetClrCardDetectSd; +extern CONST SD_COMMAND CmdAppSendScrSd; +extern CONST SD_COMMAND CmdAppSd; + +#endif // __PROTOCOL_H__ diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/RpmbIo.c b/Platform/Micros= oft/Drivers/SdMmcDxe/RpmbIo.c new file mode 100644 index 000000000000..69ca29a6aba9 --- /dev/null +++ b/Platform/Microsoft/Drivers/SdMmcDxe/RpmbIo.c @@ -0,0 +1,611 @@ +/** @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 "SdMmcHw.h" +#include "SdMmc.h" +#include "Protocol.h" + +C_ASSERT(sizeof(EFI_RPMB_DATA_PACKET) =3D=3D SD_BLOCK_LENGTH_BYTES); + +EFI_RPMB_DATA_PACKET ResultRequest =3D { + { 0 }, // Stuff + { 0 }, // MAC + { 0 }, // Data + { 0 }, // Nonce + { 0 }, // WriteCounter + { 0 }, // Address + { 0 }, // PacketCount + { 0 }, // OperationResult + { 0x00, EFI_RPMB_REQUEST_RESULT_REQUEST } // RequestType +}; + +// JEDEC Standard No. 84-A441: +// Byte order of the RPMB data frame is MSB first, e.g. Write Counter MSB = [11] +// is storing the upmost byte of the counter value. + +VOID +Uint16ToRpmbBytes ( + IN UINT16 Value, + OUT UINT8 *RpmbBytes + ) +{ + ASSERT (RpmbBytes !=3D NULL); + + RpmbBytes[0] =3D (UINT8) (Value >> 8); + RpmbBytes[1] =3D (UINT8) (Value & 0xF); +} + + +UINT16 +RpmbBytesToUint16 ( + IN CONST UINT8 *RpmbBytes + ) +{ + ASSERT (RpmbBytes !=3D NULL); + + return ((UINT16) RpmbBytes[0] << 8) | ((UINT16) RpmbBytes[1]); +} + +EFI_STATUS +RpmbRead ( + IN SDHC_INSTANCE *HostInst, + IN EFI_RPMB_DATA_PACKET *Request, + OUT EFI_RPMB_DATA_BUFFER *Response + ) +{ + EFI_STATUS Status; + + Status =3D SdhcSetBlockCount (HostInst, 1, FALSE); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSetBlockCount() failed. (Status =3D %r)", Status); + return Status; + } + + Status =3D SdhcSendDataCommand ( + HostInst, + &CmdWriteMultiBlock, + 0, // LBA argument is ignored for RPMB access, the eMMC will use inste= ad the Address + // field of the RPMB packet + sizeof (*Request), + Request); + + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "Failed to write the Read request data packet. (Status =3D %r)", + Status); + + return Status; + } + + Status =3D SdhcSetBlockCount (HostInst, Response->PacketCount, FALSE); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSetBlockCount() failed. (Status =3D %r)", Status); + return Status; + } + + Status =3D SdhcSendDataCommand ( + HostInst, + &CmdReadMultiBlock, + 0, // LBA argument is ignored for RPMB access, the eMMC will use inste= ad the Address + // field of the RPMB packet + Response->PacketCount * sizeof(*Response->Packets), + Response->Packets); + + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "Failed to read the Read request data packet. (Status =3D %r)", + Status); + + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +RpmbWrite ( + IN SDHC_INSTANCE *HostInst, + IN EFI_RPMB_DATA_BUFFER *Request + ) +{ + EFI_STATUS Status; + + Status =3D SdhcSetBlockCount (HostInst, Request->PacketCount, TRUE); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SdhcSetBlockCount() failed. (Status =3D %r)", Status); + return Status; + } + + Status =3D SdhcSendDataCommand ( + HostInst, + &CmdWriteMultiBlock, + 0, // LBA argument is ignored for RPMB access, the eMMC will use inste= ad the Address + // field of the RPMB packet + Request->PacketCount * sizeof(*Request->Packets), + Request->Packets); + + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "Failed to write the Read request data packet. (Status =3D %r)", + Status); + + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +RpmbQueryResult ( + IN SDHC_INSTANCE *HostInst, + OUT EFI_RPMB_DATA_PACKET *Response + ) +{ + EFI_STATUS Status; + EFI_RPMB_DATA_BUFFER ResponseBuffer; + + ResponseBuffer.PacketCount =3D 1; + ResponseBuffer.Packets =3D Response; + + Status =3D RpmbRead (HostInst, &ResultRequest, &ResponseBuffer); + if (EFI_ERROR (Status)) { + LOG_ERROR ("RpmbRead() failed. (Status =3D %r)", Status); + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +RpmbProgramKeyRequest ( + IN SDHC_INSTANCE *HostInst, + IN EFI_RPMB_DATA_PACKET *Request, + OUT EFI_RPMB_DATA_PACKET *Response + ) +{ + EFI_STATUS Status; + EFI_RPMB_DATA_BUFFER RequestBuffer; + + RequestBuffer.PacketCount =3D 1; + RequestBuffer.Packets =3D Request; + + Status =3D RpmbWrite (HostInst, &RequestBuffer); + if (EFI_ERROR (Status)) { + LOG_ERROR ("RpmbWrite() failed. (Status =3D %r)", Status); + return Status; + } + + Status =3D RpmbQueryResult (HostInst, Response); + if (EFI_ERROR (Status)) { + LOG_ERROR ("RpmbQueryResult() failed. (Status =3D %r)", Status); + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +RpmbReadCounterRequest ( + IN SDHC_INSTANCE *HostInst, + IN EFI_RPMB_DATA_PACKET *Request, + OUT EFI_RPMB_DATA_PACKET *Response + ) +{ + EFI_STATUS Status; + EFI_RPMB_DATA_BUFFER ResponseBuffer; + + ResponseBuffer.PacketCount =3D 1; + ResponseBuffer.Packets =3D Response; + + Status =3D RpmbRead (HostInst, Request, &ResponseBuffer); + if (EFI_ERROR (Status)) { + LOG_ERROR ("RpmbRead() failed. (Status =3D %r)", Status); + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +RpmbAuthenticatedWriteRequest ( + IN SDHC_INSTANCE *HostInst, + IN EFI_RPMB_DATA_BUFFER *Request, + OUT EFI_RPMB_DATA_PACKET *Response + ) +{ + EFI_STATUS Status; + + Status =3D RpmbWrite (HostInst, Request); + if (EFI_ERROR (Status)) { + LOG_ERROR ("RpmbWrite() failed. (Status =3D %r)", Status); + return Status; + } + + Status =3D RpmbQueryResult (HostInst, Response); + if (EFI_ERROR (Status)) { + LOG_ERROR ("RpmbQueryResult() failed. (Status =3D %r)", Status); + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +RpmbAuthenticatedReadRequest ( + IN SDHC_INSTANCE *HostInst, + IN EFI_RPMB_DATA_PACKET *Request, + OUT EFI_RPMB_DATA_BUFFER *Response + ) +{ + EFI_STATUS Status; + + Status =3D RpmbRead (HostInst, Request, Response); + if (EFI_ERROR (Status)) { + LOG_ERROR ("RpmbRead() failed. (Status =3D %r)", Status); + return Status; + } + + return EFI_SUCCESS; +} + +VOID +RpmbHexDump ( + IN CONST UINT8 *Bytes, + IN UINTN Len + ) +{ + UINTN i; + + for (i =3D 0; i < Len; i++) { + if ((i > 0) && (i % 16) =3D=3D 0) { + LOG_VANILLA_TRACE ("\n"); + } + LOG_VANILLA_TRACE ("%02x ", *Bytes); + ++Bytes; + } + LOG_VANILLA_TRACE ("\n"); +} + +VOID +RpmbDumpPacket ( + IN EFI_RPMB_DATA_PACKET *Packet + ) +{ + LOG_TRACE ("*** RPMB Packet Dump (Packet =3D %p) ***", Packet); + LOG_TRACE ("- Write Counter"); + RpmbHexDump (Packet->WriteCounter, EFI_RPMB_PACKET_WCOUNTER_SIZE); + LOG_TRACE ("- Address:"); + RpmbHexDump (Packet->Address, EFI_RPMB_PACKET_ADDRESS_SIZE); + LOG_TRACE ("- Block Count:"); + RpmbHexDump (Packet->BlockCount, EFI_RPMB_PACKET_BLOCKCOUNT_SIZE); + LOG_TRACE ("- Result:"); + RpmbHexDump (Packet->OperationResult, EFI_RPMB_PACKET_RESULT_SIZE); + LOG_TRACE ("- Req/Res Type:"); + RpmbHexDump (Packet->RequestOrResponseType, EFI_RPMB_PACKET_TYPE_SIZE); +} + +EFI_STATUS +RpmbRequest ( + IN EFI_RPMB_IO_PROTOCOL *This, + IN EFI_RPMB_DATA_BUFFER *Request, + OUT EFI_RPMB_DATA_BUFFER *Response + ) +{ + EFI_STATUS Status; + SDHC_INSTANCE *HostInst; + MMC_EXT_CSD_PARTITION_ACCESS CurrentPartition; + EFI_STATUS SwitchStatus; + BOOLEAN SwitchPartition; + UINT16 RequestType; + + SwitchPartition =3D FALSE; + Status =3D EFI_SUCCESS; + SwitchStatus =3D EFI_SUCCESS; + + ASSERT (This); + ASSERT (Request); + ASSERT (Response); + + HostInst =3D SDHC_INSTANCE_FROM_RPMB_IO_THIS (This); + ASSERT (HostInst); + ASSERT (HostInst->HostExt); + + CurrentPartition =3D HostInst->CurrentMmcPartition; + + SwitchStatus =3D SdhcSwitchPartitionMmc (HostInst, MmcExtCsdPartitionAcc= essRpmb); + if (EFI_ERROR (SwitchStatus)) { + + LOG_ERROR ( + "SdhcSwitchPartitionMmc() failed. (SwitchStatus =3D %r)", + SwitchStatus); + + goto Exit; + } + + SwitchPartition =3D TRUE; + + ASSERT (Request->PacketCount > 0); + ASSERT (Request->Packets !=3D NULL); + RequestType =3D RpmbBytesToUint16 (Request->Packets[0].RequestOrResponse= Type); + + switch (RequestType) { + case EFI_RPMB_REQUEST_PROGRAM_KEY: + Status =3D RpmbProgramKeyRequest (HostInst, Request->Packets, Response= ->Packets); + if (EFI_ERROR (Status)) { + LOG_ERROR ("RpmbProgramKeyRequest() failed. (Status =3D %r)", Status= ); + goto Exit; + } + break; + + case EFI_RPMB_REQUEST_COUNTER_VALUE: + Status =3D RpmbReadCounterRequest (HostInst, Request->Packets, Respons= e->Packets); + if (EFI_ERROR (Status)) { + LOG_ERROR ("RpmbReadCounterRequest() failed. (Status =3D %r)", Statu= s); + goto Exit; + } + break; + + case EFI_RPMB_REQUEST_AUTH_READ: + Status =3D RpmbAuthenticatedReadRequest (HostInst, Request->Packets, R= esponse); + if (EFI_ERROR (Status)) { + LOG_ERROR ("RpmbAuthenticatedReadRequest() failed. (Status =3D %r)",= Status); + goto Exit; + } + break; + + case EFI_RPMB_REQUEST_AUTH_WRITE: + Status =3D RpmbAuthenticatedWriteRequest (HostInst, Request, Response-= >Packets); + if (EFI_ERROR (Status)) { + LOG_ERROR ("RpmbAuthenticatedWriteRequest() failed. (Status =3D %r)"= , Status); + goto Exit; + } + break; + + default: + + ASSERT (FALSE); + } + +Exit: + + if (SwitchPartition) { + SwitchStatus =3D SdhcSwitchPartitionMmc (HostInst, CurrentPartition); + if (EFI_ERROR (SwitchStatus)) { + + LOG_ERROR ( + "SdhcSwitchPartitionMmc() failed. (SwitchStatus =3D %r)", + SwitchStatus); + } + } + + if (EFI_ERROR (Status)) { + return Status; + } else { + return SwitchStatus; + } +} + +/** Authentication key programming request. + + @param[in] This Indicates a pointer to the calling context. + @param[in] ProgrammingRequest A data packet describing a key programming= request. + @param[out] ResultResponse A caller allocated data packet which will rec= eive the + key programming result. + + @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded + according to specs, other values are returned in case of any protocol er= ror. + Failure during key programming any other eMMC internal failure is report= ed + in the Result field of the returned response data packet. +**/ +EFI_STATUS +EFIAPI +RpmbIoProgramKey ( + IN EFI_RPMB_IO_PROTOCOL *This, + IN EFI_RPMB_DATA_PACKET *ProgrammingRequest, + OUT EFI_RPMB_DATA_PACKET *ResultResponse + ) +{ + EFI_STATUS Status; + EFI_RPMB_DATA_BUFFER RequestBuffer; + EFI_RPMB_DATA_BUFFER ResponseBuffer; + + LOG_TRACE ("RpmbIoProgramKey()"); + + if ((This =3D=3D NULL) || (ProgrammingRequest =3D=3D NULL) || (ResultRes= ponse =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (RpmbBytesToUint16 (ProgrammingRequest->RequestOrResponseType) !=3D E= FI_RPMB_REQUEST_PROGRAM_KEY) { + return EFI_INVALID_PARAMETER; + } + + RequestBuffer.PacketCount =3D 1; + RequestBuffer.Packets =3D ProgrammingRequest; + + ResponseBuffer.PacketCount =3D 1; + ResponseBuffer.Packets =3D ResultResponse; + + Status =3D RpmbRequest (This, &RequestBuffer, &ResponseBuffer); + if (EFI_ERROR (Status)) { + LOG_ERROR ("RpmbRequest() failed. (Status =3D %r)", Status); + return Status; + } + + return Status; +} + +/** Reading of the write counter value request. + + @param[in] This Indicates a pointer to the calling context. + @param[in] ReadRequest A data packet describing a read counter value req= uest. + @param[out] ReadResponse A caller allocated data packet which will recei= ve + the counter value read response. If counter has expired bit 7 is set to = 1 in + returned Result. + + @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded + according to specs, other values are returned in case of any protocol er= ror. + Failure during counter read or any other eMMC internal failure is report= ed + in the Result field of the returned response data packet. +**/ +EFI_STATUS +EFIAPI +RpmbIoReadCounter ( + IN EFI_RPMB_IO_PROTOCOL *This, + IN EFI_RPMB_DATA_PACKET *ReadRequest, + OUT EFI_RPMB_DATA_PACKET *ReadResponse + ) +{ + EFI_STATUS Status; + EFI_RPMB_DATA_BUFFER RequestBuffer; + EFI_RPMB_DATA_BUFFER ResponseBuffer; + + LOG_TRACE ("RpmbIoReadCounter()"); + + if ((This =3D=3D NULL) || (ReadRequest =3D=3D NULL) || (ReadResponse =3D= =3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (RpmbBytesToUint16 (ReadRequest->RequestOrResponseType) !=3D EFI_RPMB= _REQUEST_COUNTER_VALUE) { + return EFI_INVALID_PARAMETER; + } + + RequestBuffer.PacketCount =3D 1; + RequestBuffer.Packets =3D ReadRequest; + + ResponseBuffer.PacketCount =3D 1; + ResponseBuffer.Packets =3D ReadResponse; + + Status =3D RpmbRequest (This, &RequestBuffer, &ResponseBuffer); + if (EFI_ERROR (Status)) { + LOG_ERROR ("RpmbRequest() failed. (Status =3D %r)", Status); + return Status; + } + + return Status; +} + +/** Authenticated data write request. + + @param[in] This Indicates a pointer to the calling context. + @param[in] WriteRequest A sequence of data packets describing data write + requests and holds the data to be written. + @param[out] ResultResponse A caller allocated data packet which will rec= eive + the data write programming result. + + @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded + according to specs, other values are returned in case of any protocol er= ror. + Failure during data programming or any other eMMC internal failure is re= ported + in the Result field of the returned data packet. +**/ +EFI_STATUS +EFIAPI +RpmbIoAuthenticatedWrite ( + IN EFI_RPMB_IO_PROTOCOL *This, + IN EFI_RPMB_DATA_BUFFER *Request, + OUT EFI_RPMB_DATA_PACKET *Response + ) +{ + EFI_STATUS Status; + EFI_RPMB_DATA_BUFFER ResponseBuffer; + + LOG_TRACE ("RpmbIoAuthenticatedWrite()"); + + if ((This =3D=3D NULL) || (Request =3D=3D NULL) || (Response =3D=3D NULL= )) { + return EFI_INVALID_PARAMETER; + } + + if ((Request->Packets =3D=3D NULL) || (Request->PacketCount =3D=3D 0)) { + return EFI_INVALID_PARAMETER; + } + + if (RpmbBytesToUint16 (Request->Packets->RequestOrResponseType) !=3D EFI= _RPMB_REQUEST_AUTH_WRITE) { + return EFI_INVALID_PARAMETER; + } + + ResponseBuffer.PacketCount =3D 1; + ResponseBuffer.Packets =3D Response; + + Status =3D RpmbRequest (This, Request, &ResponseBuffer); + if (EFI_ERROR (Status)) { + LOG_ERROR ("RpmbRequest() failed. (Status =3D %r)", Status); + return Status; + } + + return Status; +} + +/** Authenticated data read request. + + @param[in] This Indicates a pointer to the calling context. + @param[in] ReadRequest A data packet that describes a data read request. + @param[out] ReadResponse A caller allocated data packets which will rece= ive + the data read. + + @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded + according to specs, other values are returned in case of any protocol er= ror. + Failure during data fetch from the eMMC or any other eMMC internal failu= re + is reported in the Result field of the returned data packet. +**/ +EFI_STATUS +EFIAPI +RpmbIoAuthenticatedRead ( + IN EFI_RPMB_IO_PROTOCOL *This, + IN EFI_RPMB_DATA_PACKET *ReadRequest, + OUT EFI_RPMB_DATA_BUFFER *ReadResponse + ) +{ + EFI_STATUS Status; + EFI_RPMB_DATA_BUFFER RequestBuffer; + + LOG_TRACE ("RpmbIoAuthenticatedRead()"); + + if ((This =3D=3D NULL) || (ReadRequest =3D=3D NULL) || (ReadResponse =3D= =3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((ReadResponse->Packets =3D=3D NULL) || (ReadResponse->PacketCount = =3D=3D 0)) { + return EFI_INVALID_PARAMETER; + } + + if (RpmbBytesToUint16 (ReadRequest->RequestOrResponseType) !=3D EFI_RPMB= _REQUEST_AUTH_READ) { + return EFI_INVALID_PARAMETER; + } + + RequestBuffer.PacketCount =3D 1; + RequestBuffer.Packets =3D ReadRequest; + + Status =3D RpmbRequest (This, &RequestBuffer, ReadResponse); + if (EFI_ERROR (Status)) { + LOG_ERROR ("RpmbRequest() failed. (Status =3D %r)", Status); + return Status; + } + + return Status; +} diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.c b/Platform/Microso= ft/Drivers/SdMmcDxe/SdMmc.c new file mode 100644 index 000000000000..bf4ec4ba8954 --- /dev/null +++ b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.c @@ -0,0 +1,892 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Copyright (c) 2011-2014, ARM Limited. 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 "SdMmcHw.h" +#include "SdMmc.h" +#include "Protocol.h" + +// A template EFI_BLOCK_IO media to use for creating new EFI_BLOCK_IO prot= ocols +// for new SDHC instances. +EFI_BLOCK_IO_MEDIA gSdhcMediaTemplate =3D { + 0, // MediaId + TRUE, // RemovableMedia + FALSE, // MediaPresent + FALSE, // LogicalPartition + FALSE, // ReadOnly + FALSE, // WriteCaching + SD_BLOCK_LENGTH_BYTES, // BlockSize + 4, // IoAlign + 0, // Pad + 0 // LastBlock +}; + +// This structure is serviced as a header.Its next field points to the fir= st root +// bridge device node. +LIST_ENTRY gSdhcInstancePool; +UINT32 gNextSdhcInstanceId =3D 0; + +// Event triggered by the timer to check if any cards have been removed +// or if new ones have been plugged in. +EFI_EVENT gCheckCardsEvent; + +// The ARM high-performance counter frequency. +UINT64 gHpcTicksPerSeconds =3D 0; + +VOID +EFIAPI +CheckCardsCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +EFI_STATUS +EFIAPI +UninstallAllProtocols ( + IN SDHC_INSTANCE *HostInst + ); + +BOOLEAN +EFIAPI +IsRpmbInstalledOnTheSystem ( + VOID + ); + +/** Initialize the SDHC Pool to support multiple SD/MMC devices. +**/ +VOID +InitializeSdhcPool ( + VOID + ) +{ + InitializeListHead (&gSdhcInstancePool); +} + +/** Insert a new SDHC instance in the host pool. + + @param[in] HostInst The SDHC instance context data. +**/ +VOID +InsertSdhcInstance ( + IN SDHC_INSTANCE *HostInst + ) +{ + InsertTailList (&gSdhcInstancePool, &(HostInst->Link)); +} + +/** Removes an existing SDHC instance context data from the host pool. + + @param[in] HostInst The SDHC instance data. +**/ +VOID +RemoveSdhcInstance ( + IN SDHC_INSTANCE *HostInst +) +{ + RemoveEntryList (&(HostInst->Link)); +} + +/** Creates a new SDHC instance context data. + + It initializes the context data but does not attempt to perform any hard= ware + access nor install any EFI protocol. This happens later on when a card p= resence + state changes during the card check callback. + + @param[in] HostExt The EFI_SDHC_PROTOCOL instance data to use as the bas= is for + SDHC instance context data creation. + + @retval An SDHC instance context data on successful instance creation an= d return + NULL otherwise. +**/ +SDHC_INSTANCE* +CreateSdhcInstance ( + IN EFI_SDHC_PROTOCOL *HostExt + ) +{ + EFI_STATUS Status; + SDHC_INSTANCE *HostInst =3D NULL; + + HostInst =3D AllocateZeroPool (sizeof (SDHC_INSTANCE)); + if (HostInst =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + + HostInst->Signature =3D SDHC_INSTANCE_SIGNATURE; + HostInst->InstanceId =3D gNextSdhcInstanceId; + HostInst->HostExt =3D HostExt; + + HostExt->GetCapabilities (HostExt, &HostInst->HostCapabilities); + ASSERT (HostInst->HostCapabilities.MaximumBlockSize > 0); + ASSERT (HostInst->HostCapabilities.MaximumBlockCount > 0); + + // We will support 512 byte blocks only. + if (HostInst->HostCapabilities.MaximumBlockSize < SD_BLOCK_LENGTH_BYTES)= { + LOG_ERROR ( + "Unsupported max block size of %d bytes", + HostInst->HostCapabilities.MaximumBlockSize); + Status =3D EFI_UNSUPPORTED; + goto Exit; + } + + LOG_TRACE ( + "Host Capabilities: MaximumBlockSize:%d MaximumBlockCount:%d", + HostInst->HostCapabilities.MaximumBlockSize, + HostInst->HostCapabilities.MaximumBlockCount); + + HostInst->DevicePathProtocolInstalled =3D FALSE; + HostInst->BlockIoProtocolInstalled =3D FALSE; + HostInst->RpmbIoProtocolInstalled =3D FALSE; + + // Initialize BlockIo Protocol. + + HostInst->BlockIo.Media =3D AllocateCopyPool (sizeof (EFI_BLOCK_IO_MEDIA= ), &gSdhcMediaTemplate); + if (HostInst->BlockIo.Media =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + + HostInst->BlockIo.Revision =3D EFI_BLOCK_IO_INTERFACE_REVISION; + HostInst->BlockIo.Reset =3D BlockIoReset; + HostInst->BlockIo.ReadBlocks =3D BlockIoReadBlocks; + HostInst->BlockIo.WriteBlocks =3D BlockIoWriteBlocks; + HostInst->BlockIo.FlushBlocks =3D BlockIoFlushBlocks; + + // Initialize DevicePath Protocol. + + SDHC_DEVICE_PATH *DevicePath =3D &HostInst->DevicePath; + + // Initialize device path based on SDHC DeviceId and delay SlotNode init= ialization + // until the card in Slot0 is type identified. + + DevicePath->SdhcNode.Header.Type =3D HARDWARE_DEVICE_PATH; + DevicePath->SdhcNode.Header.SubType =3D HW_VENDOR_DP; + *((UINT16*) &DevicePath->SdhcNode.Header.Length) =3D SDHC_NODE_PATH_LENG= TH; + DevicePath->SdhcId =3D HostInst->HostExt->SdhcId; + GUID SdhcDevicePathGuid =3D SDHC_DEVICE_PATH_GUID; + CopyGuid (&DevicePath->SdhcNode.Guid, &SdhcDevicePathGuid); + + SetDevicePathEndNode (&DevicePath->EndNode); + + // Initialize RpmbIo Protocol. + + HostInst->RpmbIo.Revision =3D EFI_RPMB_IO_PROTOCOL_REVISION; + HostInst->RpmbIo.AuthenticatedRead =3D RpmbIoAuthenticatedRead; + HostInst->RpmbIo.AuthenticatedWrite =3D RpmbIoAuthenticatedWrite; + HostInst->RpmbIo.ProgramKey =3D RpmbIoProgramKey; + HostInst->RpmbIo.ReadCounter =3D RpmbIoReadCounter; + + // Don't publish any protocol yet, until the SDHC device is fully initia= lized and + // ready for IO. + + ++gNextSdhcInstanceId; + + Status =3D EFI_SUCCESS; + +Exit: + if (EFI_ERROR (Status)) { + if (HostInst !=3D NULL && HostInst->BlockIo.Media !=3D NULL) { + FreePool (HostInst->BlockIo.Media); + HostInst->BlockIo.Media =3D NULL; + } + + if (HostInst !=3D NULL) { + FreePool (HostInst); + HostInst =3D NULL; + } + } + + return HostInst; +} + +/** Destroys an existing SDHC instance context data. + + It uninstalls all protocols installed on that instance, free allocated m= emory + and invokes the SDHC clean-up callback. + + @param[in] HostInst The SDHC instance context data to destroy. + + @retval EFI_SUCCESS on successful destruction and cleanup, return an EFI= error + code otherwise. +**/ +EFI_STATUS +DestroySdhcInstance ( + IN SDHC_INSTANCE *HostInst + ) +{ + EFI_STATUS Status; + + Status =3D UninstallAllProtocols (HostInst); + if (EFI_ERROR (Status)) { + return Status; + } + + // Free Memory allocated for the EFI_BLOCK_IO protocol + if (HostInst->BlockIo.Media) { + FreePool (HostInst->BlockIo.Media); + } + + HostInst->HostExt->Cleanup (HostInst->HostExt); + HostInst->HostExt =3D NULL; + + FreePool (HostInst); + + return EFI_SUCCESS; +} + +// UEFI Driver Model EFI_DRIVER_BINDING_PROTOCOL Callbacks + +/** + Tests to see if this driver supports a given controller. If a child de= vice is provided, + it further tests to see if this driver supports creating a handle for = the specified child device. + + @param This A pointer to the EFI_DRIVER_BINDING_PROTOC= OL instance. + @param ControllerHandle The handle of the controller to test. This= handle must support a protocol + interface that supplies an I/O abstraction= to the driver. Sometimes + just the presence of this I/O abstraction = is enough for the driver to + determine if it supports ControllerHandle.= Sometimes, the driver may + use the services of the I/O abstraction to= determine if this driver + supports ControllerHandle. + @param RemainingDevicePath A pointer to the remaining portion of a de= vice path. For bus drivers, + if this parameter is not NULL, then the bu= s driver must determine if + the bus controller specified by Controller= Handle and the child controller + specified by RemainingDevicePath +**/ +EFI_STATUS +EFIAPI +SdMmcDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_SDHC_PROTOCOL *HostExt; + EFI_DEV_PATH_PTR Node; + + // Check RemainingDevicePath validation. + if (RemainingDevicePath !=3D NULL) { + + // Check if RemainingDevicePath is the End of Device Path Node, + // if yes, go on checking other conditions. + if (!IsDevicePathEnd (RemainingDevicePath)) { + + // If RemainingDevicePath isn't the End of Device Path Node, + // check its validation. + + Node.DevPath =3D RemainingDevicePath; + if (Node.DevPath->Type !=3D HARDWARE_DEVICE_PATH || + Node.DevPath->SubType !=3D HW_VENDOR_DP || + DevicePathNodeLength (Node.DevPath) !=3D sizeof (VENDOR_DEVICE_P= ATH)) { + Status =3D EFI_UNSUPPORTED; + goto Exit; + } + } + } + + // Check if SDHC protocol is installed by platform. + + Status =3D gBS->OpenProtocol ( + Controller, + &gEfiSdhcProtocolGuid, + (VOID **) &HostExt, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER); + if (Status =3D=3D EFI_ALREADY_STARTED) { + Status =3D EFI_SUCCESS; + goto Exit; + } + + if (EFI_ERROR (Status)) { + goto Exit; + } + + // Close the SDHC used to perform the supported test. + gBS->CloseProtocol ( + Controller, + &gEfiSdhcProtocolGuid, + This->DriverBindingHandle, + Controller); + +Exit: + return Status; +} + +/** + Starts a device controller or a bus controller. The Start() and Stop()= services of the + EFI_DRIVER_BINDING_PROTOCOL mirror each other. + + @param This A pointer to the EFI_DRIVER_BINDING_PROTOC= OL instance. + @param ControllerHandle The handle of the controller to start. Thi= s handle must support a + protocol interface that supplies an I/O ab= straction to the driver. + @param RemainingDevicePath A pointer to the remaining portion of a de= vice path. For a bus driver, + if this parameter is NULL, then handles fo= r all the children of Controller + are created by this driver. + If this parameter is not NULL and the firs= t Device Path Node is not + the End of Device Path Node, then only the= handle for the child device + specified by the first Device Path Node of= RemainingDevicePath is created + by this driver. + If the first Device Path Node of Remaining= DevicePath is the End of Device + Path Node, no child handle is created by t= his driver. +**/ +EFI_STATUS +EFIAPI +SdMmcDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + SDHC_INSTANCE *HostInst; + EFI_SDHC_PROTOCOL *HostExt; + + LOG_TRACE ("SdMmcDriverStart()"); + + // Check RemainingDevicePath validation. + if (RemainingDevicePath !=3D NULL) { + + // Check if RemainingDevicePath is the End of Device Path Node, + // if yes, return EFI_SUCCESS. + if (IsDevicePathEnd (RemainingDevicePath)) { + Status =3D EFI_SUCCESS; + goto Exit; + } + } + + // Get the SDHC protocol. + + Status =3D gBS->OpenProtocol ( + Controller, + &gEfiSdhcProtocolGuid, + (VOID **) &HostExt, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER); + if (EFI_ERROR (Status)) { + if (Status =3D=3D EFI_ALREADY_STARTED) { + Status =3D EFI_SUCCESS; + } + goto Exit; + } + + HostInst =3D CreateSdhcInstance (HostExt); + if (HostInst !=3D NULL) { + HostInst->MmcHandle =3D Controller; + InsertSdhcInstance (HostInst); + + LOG_INFO ( + "SDHC%d instance creation completed. Detecting card presence...", + HostInst->HostExt->SdhcId); + + // Detect card presence now which will initialize the SDHC. + CheckCardsCallback (NULL, NULL); + } else { + LOG_ERROR ("CreateSdhcInstance failed. %r", Status); + } + +Exit: + return Status; +} + +/** + Stops a device controller or a bus controller. The Start() and Stop() = services of the + EFI_DRIVER_BINDING_PROTOCOL mirror each other. + + @param This A pointer to the EFI_DRIVER_BINDING_PROTOC= OL instance. + Type EFI_DRIVER_BINDING_PROTOCOL is define= d in Section 10.1. + @param ControllerHandle A handle to the device being stopped. The = handle must support a bus + specific I/O protocol for the driver to us= e to stop the device. + @param NumberOfChildren The number of child device handles in Chil= dHandleBuffer. + @param ChildHandleBuffer An array of child handles to be freed. May= be NULL if NumberOfChildren is 0. +**/ +EFI_STATUS +EFIAPI +SdMmcDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status =3D EFI_SUCCESS; + LIST_ENTRY *CurrentLink; + SDHC_INSTANCE *HostInst; + + LOG_TRACE ("SdMmcDriverStop()"); + + // For each registered SDHC instance. + CurrentLink =3D gSdhcInstancePool.ForwardLink; + while (CurrentLink !=3D NULL && CurrentLink !=3D &gSdhcInstancePool && (= Status =3D=3D EFI_SUCCESS)) { + HostInst =3D SDHC_INSTANCE_FROM_LINK (CurrentLink); + ASSERT (HostInst !=3D NULL); + + // Close gEfiMmcHostProtocolGuid opened on the SDHC. + Status =3D gBS->CloseProtocol ( + Controller, + &gEfiSdhcProtocolGuid, + (VOID **) &HostInst->HostExt, + This->DriverBindingHandle); + + // Remove SDHC instance from the pool. + RemoveSdhcInstance (HostInst); + + // Destroy SDHC instance. + DestroySdhcInstance (HostInst); + } + + return Status; +} + +EFI_STATUS +EFIAPI +SoftReset ( + IN SDHC_INSTANCE *HostInst + ) +{ + EFI_SDHC_PROTOCOL *HostExt =3D HostInst->HostExt; + EFI_STATUS Status; + CHAR16 *DevicePathText =3D NULL; + + ASSERT (HostInst->HostExt !=3D NULL); + LOG_TRACE ("Performing Soft-Reset for SDHC%d", HostExt->SdhcId); + + Status =3D UninstallAllProtocols (HostInst); + if (EFI_ERROR (Status)) { + goto Exit; + } + + HostInst->SlotInitialized =3D FALSE; + + // Clear all media settings regardless of card presence. + HostInst->BlockIo.Media->MediaId =3D 0; + HostInst->BlockIo.Media->RemovableMedia =3D FALSE; + HostInst->BlockIo.Media->MediaPresent =3D FALSE; + HostInst->BlockIo.Media->LogicalPartition =3D FALSE; + HostInst->BlockIo.Media->WriteCaching =3D FALSE; + HostInst->BlockIo.Media->BlockSize =3D 0; + HostInst->BlockIo.Media->IoAlign =3D 4; + HostInst->BlockIo.Media->LastBlock =3D 0; + HostInst->BlockIo.Media->LowestAlignedLba =3D 0; + HostInst->BlockIo.Media->LogicalBlocksPerPhysicalBlock =3D 0; + HostInst->BlockIo.Media->OptimalTransferLengthGranularity =3D 0; + HostInst->BlockIo.Media->ReadOnly =3D FALSE; + + HostInst->RpmbIo.ReliableSectorCount =3D 0; + HostInst->RpmbIo.RpmbSizeMult =3D 0; + ZeroMem (HostInst->RpmbIo.Cid, sizeof (HostInst->RpmbIo.Cid)); + + HostInst->BlockIo.Media->MediaPresent =3D HostInst->HostExt->IsCardPrese= nt (HostInst->HostExt); + if (!HostInst->BlockIo.Media->MediaPresent) { + // Even if the media is not present, we`d like to communicate that sta= tus up + // to the storage stack by means of installing the BlockIo protocol. + Status =3D + gBS->InstallMultipleProtocolInterfaces ( + &HostInst->MmcHandle, + &gEfiBlockIoProtocolGuid, + &HostInst->BlockIo, + NULL); + + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "SoftReset(): Failed installing EFI_BLOCK_IO_PROTOCOL interface. %= r", + Status); + + goto Exit; + } + + HostInst->BlockIoProtocolInstalled =3D TRUE; + LOG_INFO ("SDHC%d media not present, skipping device initialization", = HostExt->SdhcId); + goto Exit; + } else { + HostInst->BlockIo.Media->ReadOnly =3D HostExt->IsReadOnly (HostExt); + if (HostInst->BlockIo.Media->ReadOnly) { + LOG_INFO ("SDHC%d media is read-only", HostExt->SdhcId); + } + } + + Status =3D InitializeDevice (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SoftReset(): InitializeDevice() failed. %r", Status); + goto Exit; + } + + // Update SlotNode subtype based on the card type identified. + // Note that we only support 1 slot per SDHC, i.e It is assumed that no = more + // than 1 SD/MMC card connected to the same SDHC block on the system. + SDHC_DEVICE_PATH *DevicePath =3D &HostInst->DevicePath; + if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionSd) { + DevicePath->SlotNode.SD.Header.Type =3D MESSAGING_DEVICE_PATH; + DevicePath->SlotNode.SD.Header.SubType =3D MSG_SD_DP; + *((UINT16*) &DevicePath->SlotNode.SD.Header.Length) =3D sizeof (SD_DEV= ICE_PATH); + DevicePath->SlotNode.SD.SlotNumber =3D 0; + } else { + ASSERT (HostInst->CardInfo.CardFunction =3D=3D CardFunctionMmc); + DevicePath->SlotNode.MMC.Header.Type =3D MESSAGING_DEVICE_PATH; + DevicePath->SlotNode.MMC.Header.SubType =3D MSG_EMMC_DP; + *((UINT16*) &DevicePath->SlotNode.MMC.Header.Length) =3D sizeof (EMMC_= DEVICE_PATH); + DevicePath->SlotNode.MMC.SlotNumber =3D 0; + } + + // Print a text representation of the Slot device path. + DevicePathText =3D ConvertDevicePathToText ((EFI_DEVICE_PATH_PROTOCOL*) = DevicePath, FALSE, FALSE); + + if (DevicePathText =3D=3D NULL) { + LOG_ERROR ("SoftReset(): ConvertDevicePathToText() failed."); + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + + LOG_INFO ("Recognized device: %s", DevicePathText); + + Status =3D + gBS->InstallMultipleProtocolInterfaces ( + &HostInst->MmcHandle, + &gEfiBlockIoProtocolGuid, + &HostInst->BlockIo, + NULL); + + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "SoftReset(): Failed installing EFI_BLOCK_IO_PROTOCOL interface. %r"= , + Status); + + goto Exit; + } + + HostInst->BlockIoProtocolInstalled =3D TRUE; + + Status =3D + gBS->InstallMultipleProtocolInterfaces ( + &HostInst->MmcHandle, + &gEfiDevicePathProtocolGuid, + &HostInst->DevicePath, + NULL); + + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "SoftReset(): Failed installing EFI_DEVICE_PATH_PROTOCOL interface. = %r", + Status); + + goto Exit; + } + + HostInst->DevicePathProtocolInstalled =3D TRUE; + + if (HostInst->CardInfo.CardFunction =3D=3D CardFunctionMmc) { + + if (!IsRpmbInstalledOnTheSystem ()) { + Status =3D + gBS->InstallMultipleProtocolInterfaces ( + &HostInst->MmcHandle, + &gEfiRpmbIoProtocolGuid, + &HostInst->RpmbIo, + NULL); + + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "SoftReset(): Failed installing EFI_RPMB_IO_PROTOCOL interface. = %r", + Status); + + goto Exit; + } + + LOG_INFO ("RpmbIo protocol installed for MMC: %s", DevicePathText); + + HostInst->RpmbIoProtocolInstalled =3D TRUE; + + // Track current partition in a separate variable to void having to + // ready the MMC EXT_CSD everytime we do partition switch to have + // an updated current partition. SdhostSwitchPartitionMmc will keep + // track of that variable. + + MMC_EXT_CSD_PARTITION_CONFIG partConfig; + partConfig.AsUint8 =3D HostInst->CardInfo.Registers.Mmc.ExtCsd.Parti= tionConfig; + HostInst->CurrentMmcPartition =3D + (MMC_EXT_CSD_PARTITION_ACCESS) partConfig.Fields.PARTITION_ACCESS; + + } else { + LOG_ERROR ( + "SoftReset(): RpmbIo protocol is already installed on the system. = " + "The requirement is that only 1 MMC on the system should have Rpmb= Io " + "protocol installed. Skipping RpmbIo protocol installation for %s"= , + DevicePathText); + } + } + + LOG_TRACE ("All required protocols installed successfully for %s", Devic= ePathText); + +Exit: + + // On error we should uninstall all protocols except BlockIo, it should + // always be present since it represents the SDHC physical existance not + // the card, other protocols are card dependant and are pure representat= ion + // of one or more card features + if (EFI_ERROR (Status)) { + if (HostInst->RpmbIoProtocolInstalled) { + Status =3D + gBS->UninstallMultipleProtocolInterfaces ( + HostInst->MmcHandle, + &gEfiRpmbIoProtocolGuid, + &HostInst->RpmbIo, + NULL); + + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "SoftReset(): Failed to uninstall EFI_RPMB_IO_PROTOCOL interface= . %r", + Status); + } else { + HostInst->RpmbIoProtocolInstalled =3D FALSE; + } + } + + if (HostInst->DevicePathProtocolInstalled) { + Status =3D + gBS->UninstallMultipleProtocolInterfaces ( + HostInst->MmcHandle, + &gEfiDevicePathProtocolGuid, + &HostInst->DevicePath, + NULL); + + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "SoftReset(): Failed to uninstall EFI_DEVICE_PATH_PROTOCOL inter= face. %r", + Status); + } else { + HostInst->DevicePathProtocolInstalled =3D FALSE; + } + } + } + + if (DevicePathText !=3D NULL) { + FreePool (DevicePathText); + } + + return Status; +} + +VOID +EFIAPI +CheckCardsCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + LIST_ENTRY *CurrentLink; + SDHC_INSTANCE *HostInst; + EFI_STATUS Status; + BOOLEAN IsCardPresent; + BOOLEAN CardEjected; + BOOLEAN CardInserted; + + // For each registered SDHC instance + CurrentLink =3D gSdhcInstancePool.ForwardLink; + while (CurrentLink !=3D NULL && CurrentLink !=3D &gSdhcInstancePool) { + HostInst =3D SDHC_INSTANCE_FROM_LINK (CurrentLink); + ASSERT (HostInst !=3D NULL); + + IsCardPresent =3D HostInst->HostExt->IsCardPresent (HostInst->HostExt)= ; + + // If card is present and not initialized or card no more present but = was previously + // initialized, then reset the instance + // + // Present Initialized Outcome + // T T No action + // T F Reset + // F T Reset + // F F No action + + CardEjected =3D HostInst->BlockIo.Media->MediaPresent && !IsCardPresen= t; + if (CardEjected) { + LOG_INFO ("Card ejected from SDHC%d slot", HostInst->HostExt->SdhcId= ); + } + + CardInserted =3D !HostInst->BlockIo.Media->MediaPresent && IsCardPrese= nt; + if (CardInserted) { + LOG_INFO ("Card inserted into SDHC%d slot", HostInst->HostExt->SdhcI= d); + } + + if (CardEjected || CardInserted) { + Status =3D SoftReset (HostInst); + if (EFI_ERROR (Status)) { + LOG_ERROR ("SoftReset() failed. %r", Status); + } + } + + CurrentLink =3D CurrentLink->ForwardLink; + } +} + +BOOLEAN +EFIAPI +IsRpmbInstalledOnTheSystem ( + VOID + ) +{ + EFI_STATUS Status; + EFI_RPMB_IO_PROTOCOL rpmbIo; + + Status =3D gBS->LocateProtocol ( + &gEfiRpmbIoProtocolGuid, + NULL, + (VOID **) &rpmbIo); + if (EFI_ERROR (Status)) { + return FALSE; + } + + return TRUE; +} + +EFI_STATUS +EFIAPI +UninstallAllProtocols ( + IN SDHC_INSTANCE *HostInst + ) +{ + EFI_STATUS Status; + + LOG_TRACE ("Uninstalling SDHC%d all protocols", HostInst->HostExt->SdhcI= d); + + if (HostInst->BlockIoProtocolInstalled) { + Status =3D + gBS->UninstallMultipleProtocolInterfaces ( + HostInst->MmcHandle, + &gEfiBlockIoProtocolGuid, + &HostInst->BlockIo, + NULL); + + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "UninstallAllProtocols(): Failed to uninstall EFI_BLOCK_IO_PROTOCO= L. " + "(Status =3D %r)", + Status); + + return Status; + } + + HostInst->BlockIoProtocolInstalled =3D FALSE; + } + + if (HostInst->RpmbIoProtocolInstalled) { + Status =3D + gBS->UninstallMultipleProtocolInterfaces ( + HostInst->MmcHandle, + &gEfiRpmbIoProtocolGuid, + &HostInst->RpmbIo, + NULL); + + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "UninstallAllProtocols(): Failed to uninstall EFI_RPMB_IO_PROTOCOL= . " + "(Status =3D %r)", + Status); + + return Status; + } + + HostInst->RpmbIoProtocolInstalled =3D FALSE; + } + + if (HostInst->DevicePathProtocolInstalled) { + Status =3D + gBS->UninstallMultipleProtocolInterfaces ( + HostInst->MmcHandle, + &gEfiDevicePathProtocolGuid, + &HostInst->DevicePath, + NULL); + + if (EFI_ERROR (Status)) { + LOG_ERROR ( + "UninstallAllProtocols(): Failed to uninstall EFI_DEVICE_PATH_PROT= OCOL. " + "(Status =3D %r)", + Status); + + return Status; + } + + HostInst->DevicePathProtocolInstalled =3D FALSE; + } + + return EFI_SUCCESS; +} + +EFI_DRIVER_BINDING_PROTOCOL gSdMmcDriverBindingCallbacks =3D { + SdMmcDriverSupported, + SdMmcDriverStart, + SdMmcDriverStop, + 0xa, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +SdMmcDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + LOG_TRACE ("SdMmcDxeInitialize"); + + InitializeSdhcPool (); + + // Install driver model protocols. + Status =3D EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gSdMmcDriverBindingCallbacks, + ImageHandle, + NULL, + NULL); + ASSERT_EFI_ERROR (Status); + + // Use a timer to detect if a card has been plugged in or removed. + Status =3D gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL | EVT_TIMER, + TPL_CALLBACK, + CheckCardsCallback, + NULL, + &gCheckCardsEvent); + ASSERT_EFI_ERROR (Status); + + Status =3D gBS->SetTimer ( + gCheckCardsEvent, + TimerPeriodic, + (UINT64) (10 * 1000 * SDMMC_CHECK_CARD_INTERVAL_MS)); // 200 ms + ASSERT_EFI_ERROR (Status); + + gHpcTicksPerSeconds =3D GetPerformanceCounterProperties (NULL, NULL); + ASSERT (gHpcTicksPerSeconds !=3D 0); + + return Status; +} diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.h b/Platform/Microso= ft/Drivers/SdMmcDxe/SdMmc.h new file mode 100644 index 000000000000..c5c363fb963c --- /dev/null +++ b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.h @@ -0,0 +1,529 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Copyright (c) 2011-2014, ARM Limited. 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 __SDMMC_H__ +#define __SDMMC_H__ + +// Define with non-zero to collect IO statistics and dump it to the termin= al. +#define SDMMC_COLLECT_STATISTICS 0 + +// Define with non-zero to benchmark IO on the first MmcReadBlocks call an= d +// dump to the terminal. +#define SDMMC_BENCHMARK_IO 0 + +// Lower bound of 2s poll wait time (200 x 10ms) +#define SDMMC_POLL_WAIT_COUNT 200 +#define SDMMC_POLL_WAIT_TIME_US 10000 + +// The period at which to check the presence state of each card on each +// registered SDHC instance. +#define SDMMC_CHECK_CARD_INTERVAL_MS 1000 + +// The number of recursive error recoveries to reach before considering th= e +// failure fatal, and not attempting more error recoveries. +#define SDMMC_ERROR_RECOVERY_ATTEMPT_THRESHOLD 3 + +// Logging Macros + +#define LOG_TRACE_FMT_HELPER(FMT, ...) "SdMmc[T]:" FMT "%a\n", __VA_ARGS_= _ + +#define LOG_INFO_FMT_HELPER(FMT, ...) "SdMmc[I]:" FMT "%a\n", __VA_ARGS_= _ + +#define LOG_ERROR_FMT_HELPER(FMT, ...) \ + "SdMmc[E]:" FMT " (%a: %a, %d)\n", __VA_ARGS__ + +#define LOG_INFO(...) \ + DEBUG((DEBUG_INIT, LOG_INFO_FMT_HELPER(__VA_ARGS__, ""))) + +#define LOG_VANILLA_TRACE(...) \ + DEBUG((DEBUG_VERBOSE | DEBUG_BLKIO, __VA_ARGS__)) + +#define LOG_TRACE(...) \ + DEBUG((DEBUG_VERBOSE | DEBUG_BLKIO, LOG_TRACE_FMT_HELPER(__VA_ARGS__, ""= ))) + +#define LOG_ERROR(...) \ + DEBUG((DEBUG_ERROR, LOG_ERROR_FMT_HELPER(__VA_ARGS__, __FUNCTION__, __FI= LE__, __LINE__))) + +#define LOG_ASSERT(TXT) ASSERT(!"SdMmc[A]: " TXT "\n") + +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif // C_ASSERT + +// Perform Integer division DIVIDEND/DIVISOR and return the result rounded= up +// or down to the nearest integer, where 3.5 and 3.75 are near 4, while 3.= 25 +// is near 3. +#define INT_DIV_ROUND(DIVIDEND, DIVISOR) \ + (((DIVIDEND) + ((DIVISOR) / 2)) / (DIVISOR)) + +typedef struct { + UINT16 NumBlocks; + UINT16 Count; + UINT32 TotalTransferTimeUs; +} IoReadStatsEntry; + +// Device Path Definitions +// +// eMMC and SD device paths got introduced in UEFI 2.6 +// Remove definitions below once code base migrates to UEFI 2.6 + +#ifndef MSG_SD_DP +// SD (Secure Digital) Device Path SubType. +#define MSG_SD_DP 0x1A + +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT8 SlotNumber; +} SD_DEVICE_PATH; +#endif // MSG_SD_DP + +#ifndef MSG_EMMC_DP +// EMMC (Embedded MMC) Device Path SubType. +#define MSG_EMMC_DP 0x1D + +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT8 SlotNumber; +} EMMC_DEVICE_PATH; +#endif // MSG_EMMC_DP + +typedef struct { + VENDOR_DEVICE_PATH SdhcNode; + UINT32 SdhcId; + union { + EMMC_DEVICE_PATH MMC; + SD_DEVICE_PATH SD; + } SlotNode; + EFI_DEVICE_PATH EndNode; +} SDHC_DEVICE_PATH; + +// GUID {AAFB8DAA-7340-43AC-8D49-0CCE14812489} +#define SDHC_DEVICE_PATH_GUID \ + { 0xaafb8daa, 0x7340, 0x43ac, { 0x8d, 0x49, 0xc, 0xce, 0x14, 0x81, 0x24,= 0x89 } } + +// Size of SDHC node including the Sdhc ID field +#define SDHC_NODE_PATH_LENGTH (sizeof(VENDOR_DEVICE_PATH) + sizeof(UINT32)= ) + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + UINT32 InstanceId; + EFI_HANDLE MmcHandle; + BOOLEAN SlotInitialized; + BOOLEAN Disabled; + SDHC_DEVICE_PATH DevicePath; + EFI_BLOCK_IO_PROTOCOL BlockIo; + EFI_RPMB_IO_PROTOCOL RpmbIo; + EFI_SDHC_PROTOCOL *HostExt; + SDHC_CAPABILITIES HostCapabilities; + BOOLEAN DevicePathProtocolInstalled; + BOOLEAN BlockIoProtocolInstalled; + BOOLEAN RpmbIoProtocolInstalled; + MMC_EXT_CSD_PARTITION_ACCESS CurrentMmcPartition; + CARD_INFO CardInfo; + UINT32 BlockBuffer[SD_BLOCK_WORD_COUNT]; + UINT32 CmdResponse[4]; + CONST SD_COMMAND *PreLastSuccessfulCmd; + CONST SD_COMMAND *LastSuccessfulCmd; + UINT32 ErrorRecoveryAttemptCount; +#ifdef MMC_COLLECT_STATISTICS + IoReadStatsEntry IoReadStats[1024]; + UINT32 IoReadStatsNumEntries; +#endif // COLLECT_IO_STATISTICS +} SDHC_INSTANCE; + +#define SDHC_INSTANCE_SIGNATURE SIGNATURE_32('s', 'd', 'h', 'c') +#define SDHC_INSTANCE_FROM_BLOCK_IO_THIS(a) \ + CR(a, SDHC_INSTANCE, BlockIo, SDHC_INSTANCE_SIGNATURE) +#define SDHC_INSTANCE_FROM_LINK(a) \ + CR(a, SDHC_INSTANCE, Link, SDHC_INSTANCE_SIGNATURE) +#define SDHC_INSTANCE_FROM_RPMB_IO_THIS(a) \ + CR (a, SDHC_INSTANCE, RpmbIo, SDHC_INSTANCE_SIGNATURE) + +// The ARM high-performance counter frequency +extern UINT64 gHpcTicksPerSeconds; + +// EFI_BLOCK_IO Protocol Callbacks + +/** + Reset the block device. + + This function implements EFI_BLOCK_IO_PROTOCOL.Reset(). + It resets the block device hardware. + ExtendedVerification is ignored in this implementation. + + @param This Indicates a pointer to the calling contex= t. + @param ExtendedVerification Indicates that the driver may perform a m= ore exhaustive + verification operation of the device duri= ng reset. + + @retval EFI_SUCCESS The block device was reset. + @retval EFI_DEVICE_ERROR The block device is not functioning corre= ctly and could not be reset. + +**/ +EFI_STATUS +EFIAPI +BlockIoReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Reads the requested number of blocks from the device. + + This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks(). + It reads the requested number of blocks from the device. + All the blocks are read, or an error is returned. + + @param This Indicates a pointer to the calling contex= t. + @param MediaId The media ID that the read request is for= . + @param Lba The starting logical block address to rea= d from on the device. + @param BufferSize The size of the Buffer in bytes. + This must be a multiple of the intrinsic = block size of the device. + @param Buffer A pointer to the destination buffer for t= he data. The caller is + responsible for either having implicit or= explicit ownership of the buffer. + + @retval EFI_SUCCESS The data was read correctly from the devi= ce. + @retval EFI_DEVICE_ERROR The device reported an error while attemp= ting to perform the read operation. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multipl= e of the intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are n= ot valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +BlockIoReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +/** + Writes a specified number of blocks to the device. + + This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks(). + It writes a specified number of blocks to the device. + All blocks are written, or an error is returned. + + @param This Indicates a pointer to the calling contex= t. + @param MediaId The media ID that the write request is fo= r. + @param Lba The starting logical block address to be = written. + @param BufferSize The size of the Buffer in bytes. + This must be a multiple of the intrinsic = block size of the device. + @param Buffer Pointer to the source buffer for the data= . + + @retval EFI_SUCCESS The data were written correctly to the de= vice. + @retval EFI_WRITE_PROTECTED The device cannot be written to. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_DEVICE_ERROR The device reported an error while attemp= ting to perform the write operation. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multipl= e of the intrinsic + block size of the device. + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are = not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +BlockIoWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +/** + Flushes all modified data to a physical block device. + + @param This Indicates a pointer to the calling contex= t. + + @retval EFI_SUCCESS All outstanding data were written correct= ly to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attemp= ting to write data. + @retval EFI_NO_MEDIA There is no media in the device. + +**/ +EFI_STATUS +EFIAPI +BlockIoFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ); + +// EFI_RPMPB_IO Protocol Callbacks + +/** Authentication key programming request. + + @param[in] This Indicates a pointer to the calling context. + @param[in] ProgrammingRequest A data packet describing a key programming= request. + @param[out] ResultResponse A caller allocated data packet which will rec= eive the + key programming result. + + @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded + according to specs, other values are returned in case of any protocol er= ror. + Failure during key programming any other eMMC internal failure is report= ed + in the Result field of the returned response data packet. +**/ +EFI_STATUS +EFIAPI +RpmbIoProgramKey ( + IN EFI_RPMB_IO_PROTOCOL *This, + IN EFI_RPMB_DATA_PACKET *Request, + OUT EFI_RPMB_DATA_PACKET *ResultResponse + ); + +/** Reading of the write counter value request. + + @param[in] This Indicates a pointer to the calling context. + @param[in] ReadRequest A data packet describing a read counter value req= uest. + @param[out] ReadResponse A caller allocated data packet which will recei= ve + the counter value read response. If counter has expired bit 7 is set to = 1 in + returned Result. + + @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded + according to specs, other values are returned in case of any protocol er= ror. + Failure during counter read or any other eMMC internal failure is report= ed + in the Result field of the returned response data packet. +**/ +EFI_STATUS +EFIAPI +RpmbIoReadCounter ( + IN EFI_RPMB_IO_PROTOCOL *This, + IN EFI_RPMB_DATA_PACKET *ReadRequest, + OUT EFI_RPMB_DATA_PACKET *ReadResponse + ); + +/** Authenticated data write request. + + @param[in] This Indicates a pointer to the calling context. + @param[in] WriteRequest A sequence of data packets describing data write + requests and holds the data to be written. + @param[out] ResultResponse A caller allocated data packet which will rec= eive + the data write programming result. + + @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded + according to specs, other values are returned in case of any protocol er= ror. + Failure during data programming or any other eMMC internal failure is re= ported + in the Result field of the returned data packet. +**/ +EFI_STATUS +EFIAPI +RpmbIoAuthenticatedWrite ( + IN EFI_RPMB_IO_PROTOCOL *This, + IN EFI_RPMB_DATA_BUFFER *WriteRequest, + OUT EFI_RPMB_DATA_PACKET *ResultResponse + ); + +/** Authenticated data read request. + + @param[in] This Indicates a pointer to the calling context. + @param[in] ReadRequest A data packet that describes a data read request. + @param[out] ReadResponse A caller allocated data packets which will rece= ive + the data read. + + @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded + according to specs, other values are returned in case of any protocol er= ror. + Failure during data fetch from the eMMC or any other eMMC internal failu= re + is reported in the Result field of the returned data packet. +**/ +EFI_STATUS +EFIAPI +RpmbIoAuthenticatedRead ( + IN EFI_RPMB_IO_PROTOCOL *This, + IN EFI_RPMB_DATA_PACKET *ReadRequest, + OUT EFI_RPMB_DATA_BUFFER *ReadResponse + ); + +// Helper Functions + +EFI_STATUS +EFIAPI +SoftReset ( + IN SDHC_INSTANCE *HostInst + ); + +// Debugging Helpers + +VOID +PrintCsd ( + IN SDHC_INSTANCE *HostInst + ); + +VOID +PrintCid ( + IN SDHC_INSTANCE *HostInst + ); + +VOID +PrintCardStatus ( + IN SDHC_INSTANCE *HostInst, + IN CARD_STATUS CardStatus + ); + +VOID +GetAndPrintCardStatus ( + IN SDHC_INSTANCE *HostInst + ); + +// Inlined Helper Functions + +__inline__ +static +CONST CHAR8* +MmcPartitionAccessToString ( + IN MMC_EXT_CSD_PARTITION_ACCESS Partition + ) +{ + switch (Partition) { + case MmcExtCsdPartitionAccessUserArea: + return "UserArea"; + case MmcExtCsdPartitionAccessBootPartition1: + return "Boot1"; + case MmcExtCsdPartitionAccessBootPartition2: + return "Boot2"; + case MmcExtCsdPartitionAccessRpmb: + return "RPMB"; + case MmcExtCsdPartitionAccessGpp1: + return "GeneralPurpose1"; + case MmcExtCsdPartitionAccessGpp2: + return "GeneralPurpose2"; + case MmcExtCsdPartitionAccessGpp3: + return "GeneralPurpose3"; + case MmcExtCsdPartitionAccessGpp4: + return "GeneralPurpose4"; + default: + return "Unknown"; + } +} + +__inline__ +static +CONST CHAR8* +CardStateToString ( + IN CARD_STATE State + ) +{ + switch (State) { + case CardStateIdle: + return "Idle"; + case CardStateReady: + return "Ready"; + case CardStateIdent: + return "Ident"; + case CardStateStdby: + return "Stdby"; + case CardStateTran: + return "Tran"; + case CardStateData: + return "Data"; + case CardStateRcv: + return "Rcv"; + case CardStatePrg: + return "Prg"; + case CardStateDis: + return "Dis"; + case CardStateBtst: + return "Btst"; + case CardStateSlp: + return "Slp"; + default: + return "Reserved"; + } +} + +__inline__ +static +BOOLEAN +IsCardStatusError ( + IN SDHC_INSTANCE *HostInst, + IN CARD_STATUS CardStatus + ) +{ + ASSERT (HostInst !=3D NULL); + + switch (HostInst->CardInfo.CardFunction) { + case CardFunctionSd: + return CardStatus.AsUint32 & SD_CARD_STATUS_ERROR_MASK; + case CardFunctionMmc: + return CardStatus.AsUint32 & MMC_CARD_STATUS_ERROR_MASK; + default: + ASSERT (FALSE); + return FALSE; + } +} + +__inline__ +static +BOOLEAN +CmdsAreEqual ( + IN CONST SD_COMMAND *Left, + IN CONST SD_COMMAND *Right + ) +{ + ASSERT (Left !=3D NULL); + ASSERT (Right !=3D NULL); + + if (Left !=3D Right) { + return (Left->Class =3D=3D Right->Class) && + (Left->Index =3D=3D Right->Index) && + (Left->ResponseType =3D=3D Right->ResponseType) && + (Left->TransferDirection =3D=3D Right->TransferDirection) && + (Left->TransferType =3D=3D Right->TransferType) && + (Left->Type =3D=3D Right->Type); + } + + return TRUE; +} + +// Timing Helpers + +/** Gets the current high-performance counter tick count. + + The returned tick count is considered as a time stamp and can used later= in + elapsed time calculations. + + @retval Current high-performance counter tick count. +**/ +__inline__ +static +UINT64 +HpcTimerStart ( + VOID + ) +{ + return GetPerformanceCounter (); +} + +/** Calculates the elapsed milliseconds since a specific timer time stamp. + + @param[in] TimerStartTimestamp The high-performance counter tick count t= o use + as the starting point in elapsed time calculation. + + @retval The milliseconds elapsed. +**/ +__inline__ +static +UINT64 +HpcTimerElapsedMilliseconds ( + IN UINT64 TimerStartTimestamp + ) +{ + return (((GetPerformanceCounter () - TimerStartTimestamp) * 1000UL) / + gHpcTicksPerSeconds); +} + +#endif // __SDMMC_H__ diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/SdMmcDxe.inf b/Platform/Mi= crosoft/Drivers/SdMmcDxe/SdMmcDxe.inf new file mode 100644 index 000000000000..c8c45d07f1ed --- /dev/null +++ b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmcDxe.inf @@ -0,0 +1,50 @@ +# +# 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 SdMmcDxe + FILE_GUID =3D 16738C4A-8044-4DD8-B68E-58A53CEFF5D9 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + + ENTRY_POINT =3D SdMmcDxeInitialize + +[Sources.common] + SdMmc.c + BlockIo.c + Debug.c + Protocol.c + RpmbIo.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + Platform/Microsoft/MsPkg.dec + Platform/Microsoft/OpteeClientPkg/OpteeClientPkg.dec + +[LibraryClasses] + BaseLib + UefiLib + UefiDriverEntryPoint + BaseMemoryLib + TimerLib + +[Protocols] + gEfiDiskIoProtocolGuid + gEfiBlockIoProtocolGuid + gEfiDevicePathProtocolGuid + gEfiSdhcProtocolGuid + gEfiRpmbIoProtocolGuid + +[Depex] + TRUE diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/SdMmcHw.h b/Platform/Micro= soft/Drivers/SdMmcDxe/SdMmcHw.h new file mode 100644 index 000000000000..b5683a6e260d --- /dev/null +++ b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmcHw.h @@ -0,0 +1,506 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Copyright (c) 2011-2014, ARM Limited. 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 __SDMMCHW_H__ +#define __SDMMCHW_H__ + +#pragma pack(1) + +#define SD_BLOCK_LENGTH_BYTES 512 +#define SD_BLOCK_WORD_COUNT (SD_BLOCK_LENGTH_BYTES / sizeo= f (UINT32)) +#define SD_IDENT_MODE_CLOCK_FREQ_HZ 400000 // 400 KHz +#define MMC_HIGH_SPEED_MODE_CLOCK_FREQ_HZ 52000000 // 52 MHz + +typedef enum { + CardSpeedModeUndefined =3D 0, + CardSpeedModeNormalSpeed, + CardSpeedModeHighSpeed +} CARD_SPEED_MODE; + +typedef enum { + CardFunctionUnknown =3D 0, + CardFunctionSd, + CardFunctionSdio, + CardFunctionComboSdSdio, + CardFunctionMmc +} CARD_FUNCTION; + +typedef enum { + CardStateIdle =3D 0, + CardStateReady, + CardStateIdent, + CardStateStdby, + CardStateTran, + CardStateData, + CardStateRcv, + CardStatePrg, + CardStateDis, + CardStateBtst, + CardStateSlp +} CARD_STATE; + +typedef union { + UINT32 AsUint32; + struct { + UINT32 RESERVED_1 : 2; // [1:0] + UINT32 RESERVED_2 : 1; // [2] + UINT32 AKE_SEQ_ERROR : 1; // [3] SD + UINT32 RESERVED_3 : 1; // [4] + UINT32 APP_CMD : 1; // [5] + UINT32 URGENT_BKOPS : 1; // [6] MMC + UINT32 SWITCH_ERROR : 1; // [7] MMC + UINT32 READY_FOR_DATA : 1; // [8] + UINT32 CURRENT_STATE : 4; // [12:9] + UINT32 ERASE_RESET : 1; // [13] + UINT32 RESERVED_4 : 1; // [14] + UINT32 WP_ERASE_SKIP : 1; // [15] + UINT32 CID_CSD_OVERWRITE : 1; // [16] + UINT32 OVERRUN : 1; // [17] MMC + UINT32 UNDERRUN : 1; // [18] MMC + UINT32 ERROR : 1; // [19] + UINT32 CC_ERROR : 1; // [20] + UINT32 CARD_ECC_FAILED : 1; // [21] + UINT32 ILLEGAL_COMMAND : 1; // [22] + UINT32 COM_CRC_ERROR : 1; // [23] + UINT32 LOCK_UNLOCK_FAILED : 1; // [24] + UINT32 CARD_IS_LOCKED : 1; // [25] + UINT32 WP_VIOLATION : 1; // [26] + UINT32 ERASE_PARAM : 1; // [27] + UINT32 ERASE_SEQ_ERROR : 1; // [28] + UINT32 BLOCK_LEN_ERROR : 1; // [29] + UINT32 ADDRESS_MISALIGN : 1; // [30] + UINT32 ADDRESS_OUT_OF_RANGE : 1; // [31] + } Fields; +} CARD_STATUS; + +#define MMC_CARD_STATUS_ERROR_MASK \ + (BIT7 | BIT13 | BIT15 | BIT16 | BIT17 | BIT18 | BIT19 | BIT20 | = \ + BIT21 | BIT22 | BIT23 | BIT24 | BIT26 | BIT27 | BIT28 | BIT29 | = \ + BIT30 | BIT31) + +#define SD_CARD_STATUS_ERROR_MASK \ + (BIT3 | BIT13 | BIT15 | BIT16 | BIT19 | BIT20 | \ + BIT21 | BIT22 | BIT23 | BIT24 | BIT26 | BIT27 | BIT28 | BIT29 | = \ + BIT30 | BIT31) + +typedef union { + UINT32 AsUint32; + struct { + UINT32 CheckPattern : 8; + UINT32 VoltageSupplied : 4; + UINT32 RESERVED_1 : 16; + UINT32 CommandIndex : 6; + } Fields; +} SEND_IF_COND_ARG; + +typedef SEND_IF_COND_ARG SEND_IF_COND_CMD_RESPONSE; + +// definition for VoltageAccepted in SD_CMD8_STATUS + +#define SD_CMD8_VOLTAGE_27_36 0x01 +#define SD_CMD8_VOLTAGE_LOW 0x02 + +typedef union { + UINT32 AsUint32; + struct { + UINT32 VoltageWindow : 24; // [23:0] Maps to OCR[0:23] + UINT32 S18R : 1; // [24] Switching to 1.8V Request + // 0b: Use Current signal voltage, 1b: Swi= tch to 1.8V signal voltage + + UINT32 RESERVED_1 : 3; // [27:25] + UINT32 XPC : 1; // SDXC Power Control [28] 0b: Power Savin= g, 1b: Max Performance + UINT32 RESERVED_2 : 1; // [29] + UINT32 HCS : 1; // Host Capacity Support [30] 0b: SDSC, 1b= : SDHC or SDXC + UINT32 RESERVED_3 : 1; // [31] + } Fields; +} SD_SEND_OP_COND_ARG; + +typedef union { + UINT32 AsUint32; + struct { + UINT32 VoltageWindow : 24; // [23:0] Voltage profile + UINT32 RESERVED_1 : 5; // Reserved + UINT32 AccessMode : 2; // 00b (byte mode), 10b (sector mode) + UINT32 PowerUp : 1; // This bit is set to LOW if the card has = not finished the power up routine + } Fields; +} SD_OCR; + +typedef union { + UINT32 AsUint32; + struct { + UINT32 VoltageWindow : 24; // [23:0] Voltage profile + UINT32 S18A : 1; // [24] Switching to 1.8V Accepted + UINT32 RESERVED_1 : 5; // Reserved [29:25] + UINT32 CCS : 1; // Card Capacity Status [30] + UINT32 PowerUp : 1; // This bit is set to LOW if the card has = not finished the power up routine [31] + } Fields; +} SD_OCR_EX; + +typedef struct { + UINT16 MDT : 12; // Manufacturing date [19:8] + UINT16 RESERVED_1 : 4; // Reserved [23:20] + UINT32 PSN; // Product serial number [55:24] + UINT8 PRV; // Product revision [63:56] + UINT8 PNM[5]; // Product name [64:103] + UINT16 OID; // OEM/Application ID [119:104] + UINT8 MID; // Manufacturer ID [127:120] +} SD_CID; + +typedef struct { + UINT16 MDT : 8; // Manufacturing date [15:8] + UINT32 PSN; // Product serial number [47:16] + UINT8 PRV; // Product revision [55:48] + UINT8 PNM[6]; // Product name [103:56] + UINT8 OID; // OEM/Application ID [111:104] + UINT8 CBX : 2; // Card/BGA [113:112] + UINT8 RESERVED_1 : 6; // [119:114] + UINT8 MID; // Manufacturer ID [127:120] +} MMC_CID; + +typedef struct { + UINT8 RESERVED_1 : 2; // Reserved [9:8] + UINT8 FILE_FORMAT : 2; // File format [11:10] + UINT8 TMP_WRITE_PROTECT : 1; // Temporary write protection [12:12] + UINT8 PERM_WRITE_PROTECT : 1; // Permanent write protection [13:13] + UINT8 COPY : 1; // Copy flag (OTP) [14:14] + UINT8 FILE_FORMAT_GRP : 1; // File format group [15:15] + UINT16 RESERVED_2 : 5; // Reserved [20:16] + UINT16 WRITE_BL_PARTIAL : 1; // Partial blocks for write allowed [21:= 21] + UINT16 WRITE_BL_LEN : 4; // Max. write data block length [25:22] + UINT16 R2W_FACTOR : 3; // Write speed factor [28:26] + UINT16 RESERVED_3 : 2; // Reserved [30:29] + UINT16 WP_GRP_ENABLE : 1; // Write protect group enable [31:31] + UINT32 WP_GRP_SIZE : 7; // Write protect group size [38:32] + UINT32 SECTOR_SIZE : 7; // Erase sector size [45:39] + UINT32 ERASE_BLK_EN : 1; // Erase single block enable [46:46] + UINT32 C_SIZE_MULT : 3; // Device size multiplier [49:47] + UINT32 VDD_W_CURR_MAX : 3; // Max. write current @ VDD max [52:50] + UINT32 VDD_W_CURR_MIN : 3; // Max. write current @ VDD min [55:53] + UINT32 VDD_R_CURR_MAX : 3; // Max. read current @ VDD max [58:56] + UINT32 VDD_R_CURR_MIN : 3; // Max. read current @ VDD min [61:59] + UINT32 C_SIZELow2 : 2; // Device size [63:62] + UINT32 C_SIZEHigh10 : 10; // Device size [73:64] + UINT32 RESERVED_4 : 2; // Reserved [75:74] + UINT32 DSR_IMP : 1; // DSR implemented [76:76] + UINT32 READ_BLK_MISALIGN : 1; // Read block misalignment [77:77] + UINT32 WRITE_BLK_MISALIGN : 1; // Write block misalignment [78:78] + UINT32 READ_BL_PARTIAL : 1; // Partial blocks for read allowed [79:7= 9] + UINT32 READ_BL_LEN : 4; // Max. read data block length [83:80] + UINT32 CCC : 12; // Card command classes [95:84] + UINT8 TRAN_SPEED; // Max. bus clock frequency [103:96] + UINT8 NSAC; // Data read access-time 2 in CLK cycles= (NSAC*100) [111:104] + UINT8 TAAC; // Data read access-time 1 [119:112] + UINT8 RESERVED_5 : 6; // Reserved [125:120] + UINT8 CSD_STRUCTURE : 2; // CSD structure [127:126] +} SD_CSD; + +typedef struct { + UINT8 RESERVED_1 : 2; // Reserved [9:8] + UINT8 FILE_FORMAT : 2; // File format [11:10] + UINT8 TMP_WRITE_PROTECT : 1; // Temporary write protection [12:12] + UINT8 PERM_WRITE_PROTECT : 1; // Permanent write protection [13:13] + UINT8 COPY : 1; // Copy flag (OTP) [14:14] + UINT8 FILE_FORMAT_GRP : 1; // File format group [15:15] + UINT16 RESERVED_2 : 5; // Reserved [20:16] + UINT16 WRITE_BL_PARTIAL : 1; // Partial blocks for write allowed [21:= 21] + UINT16 WRITE_BL_LEN : 4; // Max. write data block length [25:22] + UINT16 R2W_FACTOR : 3; // Write speed factor [28:26] + UINT16 RESERVED_3 : 2; // Reserved [30:29] + UINT16 WP_GRP_ENABLE : 1; // Write protect group enable [31:31] + UINT16 WP_GRP_SIZE : 7; // Write protect group size [38:32] + UINT16 SECTOR_SIZE : 7; // Erase sector size [45:39] + UINT16 ERASE_BLK_EN : 1; // Erase single block enable [46:46] + UINT16 RESERVED_4 : 1; // Reserved [47:47] + UINT32 C_SIZE : 22; // Device size [63:62] + UINT32 RESERVED_5 : 6; // Reserved [75:74] + UINT32 DSR_IMP : 1; // DSR implemented [76:76] + UINT32 READ_BLK_MISALIGN : 1; // Read block misalignment [77:77] + UINT32 WRITE_BLK_MISALIGN : 1; // Write block misalignment [78:78] + UINT32 READ_BL_PARTIAL : 1; // Partial blocks for read allowed [79:7= 9] + UINT16 READ_BL_LEN : 4; // Max. read data block length [83:80] + UINT16 CCC : 12; // Card command classes [95:84] + UINT8 TRAN_SPEED; // Max. bus clock frequency [103:96] + UINT8 NSAC; // Data read access-time 2 in CLK cycles= (NSAC*100) [111:104] + UINT8 TAAC; // Data read access-time 1 [119:112] + UINT8 RESERVED_6 : 6; // Reserved [125:120] + UINT8 CSD_STRUCTURE : 2; // CSD structure [127:126] +} SD_CSD_2; + +typedef struct { + UINT8 ECC : 2; // ECC code [9:8] + UINT8 FILE_FORMAT : 2; // File format [11:10] + UINT8 TMP_WRITE_PROTECT : 1; // Temporary write protection [12:12] + UINT8 PERM_WRITE_PROTECT : 1; // Permanent write protection [13:13] + UINT8 COPY : 1; // Copy flag (OTP) [14:14] + UINT8 FILE_FORMAT_GRP : 1; // File format group [15:15] + UINT16 CONTENT_PROT_APP : 1; // Content protection application [16:16= ] + UINT16 RESERVED_1 : 4; // Reserved [20:17] + UINT16 WRITE_BL_PARTIAL : 1; // Partial blocks for write allowed [21:= 21] + UINT16 WRITE_BL_LEN : 4; // Max. write data block length [25:22] + UINT16 R2W_FACTOR : 3; // Write speed factor [28:26] + UINT16 DEFAULT_ECC : 2; // Manufacturer default ECC [30:29] + UINT16 WP_GRP_ENABLE : 1; // Write protect group enable [31:31] + UINT32 WP_GRP_SIZE : 5; // Write protect group size [36:32] + UINT32 ERASE_GRP_MULT : 5; // Erase group size multiplier [41:37] + UINT32 ERASE_GRP_SIZE : 5; // Erase sector size [46:42] + UINT32 C_SIZE_MULT : 3; // Device size multiplier [49:47] + UINT32 VDD_W_CURR_MAX : 3; // Max. write current @ VDD max [52:50] + UINT32 VDD_W_CURR_MIN : 3; // Max. write current @ VDD min [55:53] + UINT32 VDD_R_CURR_MAX : 3; // Max. read current @ VDD max [58:56] + UINT32 VDD_R_CURR_MIN : 3; // Max. read current @ VDD min [61:59] + UINT32 C_SIZELow2 : 2; // Device size [63:62] + UINT32 C_SIZEHigh10 : 10; // Device size [73:64] + UINT32 RESERVED_4 : 2; // Reserved [75:74] + UINT32 DSR_IMP : 1; // DSR implemented [76:76] + UINT32 READ_BLK_MISALIGN : 1; // Read block misalignment [77:77] + UINT32 WRITE_BLK_MISALIGN : 1; // Write block misalignment [78:78] + UINT32 READ_BL_PARTIAL : 1; // Partial blocks for read allowed [79:7= 9] + UINT32 READ_BL_LEN : 4; // Max. read data block length [83:80] + UINT32 CCC : 12; // Card command classes [95:84] + UINT8 TRAN_SPEED; // Max. bus clock frequency [103:96] + UINT8 NSAC; // Data read access-time 2 in CLK cycles= (NSAC*100) [111:104] + UINT8 TAAC; // Data read access-time 1 [119:112] + UINT8 RESERVED_5 : 2; // Reserved [121:120] + UINT8 SPEC_VERS : 4; // System specification version [125:122= ] + UINT8 CSD_STRUCTURE : 2; // CSD structure [127:126] +} MMC_CSD; + +// We support spec version 4.X and higher +// If CSD.SPEC_VERS indicates a version 4.0 or higher, the card is a high = speed card and supports +// SWITCH and SEND_EXT_CSD commands. Otherwise the card is an old MMC card= . +#define MMC_MIN_SUPPORTED_SPEC_VERS 4 + +typedef struct { + + // Host modifiable modes + + UINT8 Reserved26[134]; + UINT8 BadBlockManagement; + UINT8 Reserved25; + UINT32 EnhancedUserDataStartAddress; + UINT8 EnhancedUserDataAreaSize[3]; + UINT8 GpPartSizeMult[12]; + UINT8 PartitioningSetting; + UINT8 PartitionsAttribute; + UINT8 MaxEnhancedAreaSize[3]; + UINT8 PartitioningSupport; + UINT8 Reserved24; + UINT8 HwResetFunc; + UINT8 Reserved23[5]; + UINT8 RpmbSizeMult; + UINT8 FwConfig; + UINT8 Reserved22; + UINT8 UserWriteProt; + UINT8 Reserved21; + UINT8 BootWriteProt; + UINT8 Reserved20; + UINT8 EraseGroupDef; + UINT8 Reserved19; + UINT8 BootBusWidth; + UINT8 BootConfigProt; + UINT8 PartitionConfig; + UINT8 Reserved18; + UINT8 ErasedMemContent; + UINT8 Reserved17; + UINT8 BusWidth; + UINT8 Reserved16; + UINT8 HighSpeedTiming; + UINT8 Reserved15; + UINT8 PowerClass; + UINT8 Reserved14; + UINT8 CmdSetRevision; + UINT8 Reserved13; + UINT8 CmdSet; + + // Non-modifiable properties + + UINT8 ExtendedCsdRevision; + UINT8 Reserved12; + UINT8 CsdStructureVersion; + UINT8 Reserved11; + UINT8 CardType; + UINT8 Reserved10[3]; + UINT8 PowerClass52Mhz195V; + UINT8 PowerClass26Mhz195V; + UINT8 PowerClass52Mhz36V; + UINT8 PowerClass26Mhz36V; + UINT8 Reserved9; + UINT8 MinReadPerf4bit26Mhz; + UINT8 MinWritePerf4bit26Mhz; + UINT8 MinReadPerf8bit26Mhz; + UINT8 MinWritePerf8bit26Mhz; + UINT8 MinReadPerf8bit52Mhz; + UINT8 MinWritePerf8bit52Mhz; + UINT8 Reserved8; + UINT32 SectorCount; + UINT8 Reserved7; + UINT8 SleepAwakeTimeout; + UINT8 Reserved6; + UINT8 SleepCurrentVccq; + UINT8 SleepCurrentVcc; + UINT8 HighCapacityWriteProtectSize; + UINT8 ReliableWriteSectorCount; + UINT8 HighCapacityEraseTimeout; + UINT8 HighCapacityEraseSize; + UINT8 AccessSize; + UINT8 BootPartitionSize; + UINT8 Reserved5; + UINT8 BootInfo; + UINT8 SecureTrimMultiplier; + UINT8 SecureEraseMultiplier; + UINT8 SecureFeatureSupport; + UINT8 TrimMultiplier; + UINT8 Reserved4; + UINT8 MinReadPerf8bit52MhzDdr; + UINT8 MinWritePerf8bit52MhzDdr; + UINT16 Reserved3; + UINT8 PowerClass52MhzDdr36V; + UINT8 PowerClass52MhzDdr195V; + UINT8 Reserved2; + UINT8 InitTimeoutAfterPartitioning; + UINT8 Reserved1[262]; + UINT8 SupportedCmdSets; + UINT8 Reserved[7]; +} MMC_EXT_CSD; + +typedef enum { + MmcExtCsdCardTypeNormalSpeed =3D 0x01, + MmcExtCsdCardTypeHighSpeed =3D 0x02, + MmcExtCsdCardTypeDdr1v8 =3D 0x04, + MmcExtCsdCardTypeDdr1v2 =3D 0x08 +} MmcExtCsdCardType; + +typedef enum { + MmcExtCsdBusWidth1Bit =3D 0, + MmcExtCsdBusWidth4Bit =3D 1, + MmcExtCsdBusWidth8Bit =3D 2 +} MmcExtCsdBusWidth; + +typedef enum { + MmcExtCsdPartitionAccessUserArea, + MmcExtCsdPartitionAccessBootPartition1, + MmcExtCsdPartitionAccessBootPartition2, + MmcExtCsdPartitionAccessRpmb, + MmcExtCsdPartitionAccessGpp1, + MmcExtCsdPartitionAccessGpp2, + MmcExtCsdPartitionAccessGpp3, + MmcExtCsdPartitionAccessGpp4, +} MMC_EXT_CSD_PARTITION_ACCESS; + +typedef enum { + MmcExtCsdBootPartitionEnableNotBootEnabled, + MmcExtCsdBootPartitionBootPartition1BootEnabled, + MmcExtCsdBootPartitionBootPartition2BootEnabled, + MmcExtCsdBootPartitionUserAreaBootEnabled =3D 7, +} MMC_EXT_CSD_BOOT_PARTITION_ENABLE; + +typedef union { + UINT8 AsUint8; + struct { + UINT8 PARTITION_ACCESS : 3; // [2:0] + UINT8 BOOT_PARTITION_ENABLE : 3; // [5:3] + UINT8 BOOT_ACK : 1; // [6] + UINT8 RESERVED_1 : 1; // [7] + } Fields; +} MMC_EXT_CSD_PARTITION_CONFIG; + +typedef enum { + MmcExtCsdBitIndexPartitionConfig =3D 179, + MmcExtCsdBitIndexBusWidth =3D 183, + MmcExtCsdBitIndexHsTiming =3D 185 +} MMC_EXT_CSD_BIT_INDEX; + +typedef enum { + MmcSwitchCmdAccessTypeCommandSet, + MmcSwitchCmdAccessTypeSetBits, + MmcSwitchCmdAccessTypeClearBits, + MmcSwitchCmdAccessTypeWriteByte +} MMC_SWITCH_CMD_ACCESS_TYPE; + +typedef union { + UINT32 AsUint32; + struct { + UINT32 CmdSet : 3; // [2:0] + UINT32 RESERVED_1 : 5; // Set to 0 [7:3] + UINT32 Value : 8; // [15:8] + UINT32 Index : 8; // [23:16] + UINT32 Access : 2; // A value from MMC_SWITCH_CMD_ACCESS_TYPE [25= :24] + UINT32 RESERVED_2 : 6; // Set to 0 [31:26] + } Fields; +} MMC_SWITCH_CMD_ARG; + +// Bits [3:0] code the current consumption for the 4 bit bus configuration +#define MMC_EXT_CSD_POWER_CLASS_4BIT(X) ((X) & 0xF) + +// Bits [7:4] code the current consumption for the 8 bit bus configuration +#define MMC_EXT_CSD_POWER_CLASS_8BIT(X) ((X) >> 4) + +typedef struct { + UINT32 RESERVED_1; + UINT32 CMD_SUPPORT : 2; + UINT32 RESERVED_2 : 9; + UINT32 EX_SECURITY : 4; + UINT32 SD_SPEC3 : 1; + UINT32 SD_BUS_WIDTH : 4; + UINT32 SD_SECURITY : 3; + UINT32 DATA_STAT_AFTER_ERASE : 1; + UINT32 SD_SPEC : 4; + UINT32 SCR_STRUCTURE : 4; +} SD_SCR; + +typedef SD_OCR MMC_OCR; +typedef SD_OCR MMC_SEND_OP_COND_ARG; + +typedef enum { + SdOcrAccessByteMode =3D 0, + SdOcrAccessSectorMode =3D 2 +} SD_OCR_ACCESS; + +// Voltage window that covers from 2.8V and up to 3.6V +#define SD_OCR_HIGH_VOLTAGE_WINDOW 0x00FF8000 + +typedef struct { + SD_OCR Ocr; + SD_CID Cid; + SD_CSD Csd; + SD_SCR Scr; +} SD_REGISTERS; + +typedef struct { + MMC_OCR Ocr; + MMC_CID Cid; + MMC_CSD Csd; + MMC_EXT_CSD ExtCsd; +} MMC_REGISTERS; + +typedef struct { + UINT32 RCA; + CARD_FUNCTION CardFunction; + BOOLEAN HasExtendedOcr; + BOOLEAN HighCapacity; + UINT64 ByteCapacity; + CARD_SPEED_MODE CurrentSpeedMode; + + union { + SD_REGISTERS Sd; + MMC_REGISTERS Mmc; + } Registers; + +} CARD_INFO; + +#pragma pack() + +#endif // __SDMMCHW_H__ + diff --git a/Platform/Microsoft/Include/Protocol/RpmbIo.h b/Platform/Micros= oft/Include/Protocol/RpmbIo.h new file mode 100644 index 000000000000..ed37f7c4fc06 --- /dev/null +++ b/Platform/Microsoft/Include/Protocol/RpmbIo.h @@ -0,0 +1,262 @@ +/** @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. +* +**/ + +/** +* +* RPMB IO protocol is an interface implementation for the Replay Protecte= d Memory +* Block (RPMB) as defined by JEDEC Standard for MultiMediaCard specs 4.41= . +* +* This protocol abstracts the RPMB operations to allow EFI boot services = environment +* to perform eMMC RPMB operations without specific knowledge about the ca= rd type or +* the host controller. +* +**/ + +#ifndef __RPMB_IO_H__ +#define __RPMB_IO_H__ + +// Global ID for the RPMB IO Protocol {FBAEE5B2-08B0-41B8-B0B0-86B72EED1BB= 6} +#define EFI_RPMB_IO_PROTOCOL_GUID \ + { 0xfbaee5b2, 0x8b0, 0x41b8, { 0xb0, 0xb0, 0x86, 0xb7, 0x2e, 0xed, 0x1b,= 0xb6 } }; + +#define EFI_RPMB_IO_PROTOCOL_REVISION 0x00010000 + +// RPMB Request Message Types + +#define EFI_RPMB_REQUEST_PROGRAM_KEY 0x0001 // Authentication key pro= gramming request +#define EFI_RPMB_REQUEST_COUNTER_VALUE 0x0002 // Reading of the Write C= ounter value -request +#define EFI_RPMB_REQUEST_AUTH_WRITE 0x0003 // Authenticated data wri= te request +#define EFI_RPMB_REQUEST_AUTH_READ 0x0004 // Authenticated data rea= d request +#define EFI_RPMB_REQUEST_RESULT_REQUEST 0x0005 // Result read request + +// RPMB Response Message Types + +#define EFI_RPMB_RESPONSE_PROGRAM_KEY 0x0100 // Authentication key pro= gramming response +#define EFI_RPMB_RESPONSE_COUNTER_VALUE 0x0200 // Reading of the Write C= ounter value -response +#define EFI_RPMB_RESPONSE_AUTH_WRITE 0x0300 // Authenticated data wri= te response +#define EFI_RPMB_RESPONSE_AUTH_READ 0x0400 // Authenticated data rea= d response + +// RPMB Operation Results + +#define EFI_RPMB_OK 0 // Operation OK +#define EFI_RPMB_ERROR_GENERAL 1 // General failure +#define EFI_RPMB_ERROR_AUTH 2 // Authentication failure (MAC = comparison not matching, MAC calculation failure) +#define EFI_RPMB_ERROR_COUNTER 3 // Counter failure (counters no= t matching in comparison, counter incrementing failure) +#define EFI_RPMB_ERROR_ADDRESS 4 // Address failure (address out= of range, wrong address alignment) +#define EFI_RPMB_ERROR_WRITE 5 // Write failure (data/counter/= result write failure) +#define EFI_RPMB_ERROR_READ 6 // Read failure (data/counter/r= esult read failure) +#define EFI_RPMB_ERROR_KEY 7 // Authentication Key not yet p= rogrammed + +#define EFI_RPMB_ERROR_MASK 0x7 +#define EFI_RPMB_ERROR_CNT_EXPIRED_BIT 0x80 + +// RPMB Data Frame fields size in bytes. + +#define EFI_RPMB_PACKET_STUFF_SIZE 196 +#define EFI_RPMB_PACKET_KEY_MAC_SIZE 32 +#define EFI_RPMB_PACKET_DATA_SIZE 256 +#define EFI_RPMB_PACKET_NONCE_SIZE 16 +#define EFI_RPMB_PACKET_WCOUNTER_SIZE 4 +#define EFI_RPMB_PACKET_ADDRESS_SIZE 2 +#define EFI_RPMB_PACKET_BLOCKCOUNT_SIZE 2 +#define EFI_RPMB_PACKET_RESULT_SIZE 2 +#define EFI_RPMB_PACKET_TYPE_SIZE 2 + +// Everything in the RPMB Data Frame is hashed except the Stuff and the MA= C itself. +#define EFI_RPMB_PACKET_DATA_HASH_SIZE ( \ + sizeof(EFI_RPMB_DATA_PACKET) - \ + offsetof(EFI_RPMB_DATA_PACKET, PacketData) \ + ) + +// CID register is 16 byte +#define EFI_RPMB_CID_SIZE 16 + +/** The data frame to access the replay protected memory area. + + NOTE: Byte order of the RPMB data frame is MSB first, e.g. Write Counter= MSB + [11] is storing the upmost byte of the counter value. +**/ +#pragma pack(1) +typedef struct { + UINT8 Stuff[EFI_RPMB_PACKET_STUFF_SIZE]; + + UINT8 KeyOrMAC[EFI_RPMB_PACKET_KEY_MAC_SIZE]; // The authen= tication key or the message authentication code (MAC) depending + // on the req= uest/response type. The MAC will be delivered in the last (or the + // only) bloc= k of data. + + UINT8 PacketData[EFI_RPMB_PACKET_DATA_SIZE]; // Data to be= written or read by signed access. + UINT8 Nonce[EFI_RPMB_PACKET_NONCE_SIZE]; // Random num= ber generated by the host for the Requests and copied to the + // Response b= y the eMMC Replay Protected Memory Block engine. + + UINT8 WriteCounter[EFI_RPMB_PACKET_WCOUNTER_SIZE]; // Counter va= lue for the total amount of the successful authenticated data write + // requests m= ade by the host. + + UINT8 Address[EFI_RPMB_PACKET_ADDRESS_SIZE]; // Address of= the data to be programmed to or read from the Replay Protected + // Memory Blo= ck. Address is the serial number of the accessed half sector + // (256B). Ad= dress argument in CMD 18 and CMD 25 will be ignored. + + UINT8 BlockCount[EFI_RPMB_PACKET_BLOCKCOUNT_SIZE]; // Number of = blocks (half sectors, 256B) requested to be read/programmed. This + // value is e= qual to the count value in CMD23 argument. + + UINT8 OperationResult[EFI_RPMB_PACKET_RESULT_SIZE]; // Includes i= nformation about the status of the write counter (valid, expired) + // and succes= sfulness of the access made to the Replay Protected Memory Block. + + UINT8 RequestOrResponseType[EFI_RPMB_PACKET_TYPE_SIZE]; // Defines th= e type of request and response to/from the memory. +} EFI_RPMB_DATA_PACKET; +#pragma pack() + +typedef struct { + EFI_RPMB_DATA_PACKET *Packets; + UINTN PacketCount; // The number of RPMB Frames/Packet= s which is + //also the number of half sectors (= 256Byte) to + // be read/programmed since each RP= BM frame + //holds 256Bytes of data. +} EFI_RPMB_DATA_BUFFER; + +typedef struct _EFI_RPMB_IO_PROTOCOL EFI_RPMB_IO_PROTOCOL; + +/** Authentication key programming request. + + @param[in] This Indicates a pointer to the calling context. + @param[in] ProgrammingRequest A data packet describing a key programming= request. + @param[out] ResultResponse A caller allocated data packet which will rec= eive the + key programming result. + + @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded + according to specs, other values are returned in case of any protocol er= ror. + Failure during key programming any other eMMC internal failure is report= ed + in the Result field of the returned response data packet. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_RPMB_PROGRAM_KEY) ( + IN EFI_RPMB_IO_PROTOCOL *This, + IN EFI_RPMB_DATA_PACKET *ProgrammingRequest, + OUT EFI_RPMB_DATA_PACKET *ResultResponse + ); + +/** Reading of the write counter value request. + + @param[in] This Indicates a pointer to the calling context. + @param[in] ReadRequest A data packet describing a read counter value req= uest. + @param[out] ReadResponse A caller allocated data packet which will recei= ve + the counter value read response. If counter has expired bit 7 is set to = 1 in + returned Result. + + @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded + according to specs, other values are returned in case of any protocol er= ror. + Failure during counter read or any other eMMC internal failure is report= ed + in the Result field of the returned response data packet. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_RPMB_READ_COUNTER) ( + IN EFI_RPMB_IO_PROTOCOL *This, + IN EFI_RPMB_DATA_PACKET *ReadRequest, + OUT EFI_RPMB_DATA_PACKET *ReadResponse + ); + +/** Authenticated data write request. + + @param[in] This Indicates a pointer to the calling context. + @param[in] WriteRequest A sequence of data packets describing data write + requests and holds the data to be written. + @param[out] ResultResponse A caller allocated data packet which will rec= eive + the data write programming result. + + @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded + according to specs, other values are returned in case of any protocol er= ror. + Failure during data programming or any other eMMC internal failure is re= ported + in the Result field of the returned data packet. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_RPMB_AUTHENTICATED_WRITE) ( + IN EFI_RPMB_IO_PROTOCOL *This, + IN EFI_RPMB_DATA_BUFFER *WriteRequest, + OUT EFI_RPMB_DATA_PACKET *ResultResponse + ); + +/** Authenticated data read request. + + @param[in] This Indicates a pointer to the calling context. + @param[in] ReadRequest A data packet that describes a data read request. + @param[out] ReadResponse A caller allocated data packets which will rece= ive + the data read. + + @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded + according to specs, other values are returned in case of any protocol er= ror. + Failure during data fetch from the eMMC or any other eMMC internal failu= re + is reported in the Result field of the returned data packet. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_RPMB_AUTHENTICATED_READ) ( + IN EFI_RPMB_IO_PROTOCOL *This, + IN EFI_RPMB_DATA_PACKET *ReadRequest, + OUT EFI_RPMB_DATA_BUFFER *ReadResponse + ); + +struct _EFI_RPMB_IO_PROTOCOL { + UINT64 Revision; + UINT8 Cid[EFI_RPMB_CID_SIZE]; // MMC Card IDentification (CID) regis= ter. + + UINT8 ReliableSectorCount; // Reliable write sector count as defi= ned by the REL_WR_SEC_C field of the + // MMC EXT_CSD register. + + UINT8 RpmbSizeMult; // RPMB sector size multiplier as defi= ned by the RPMB_SIZE_MULT field of the + // MMC EXT_CSD register. + // The RPMB partition size is calculat= ed from the register by using the + // following equation: RPMB partition = size =3D 128kB x RPMB_SIZE_MULT + + // Protocol Callbacks + + EFI_RPMB_PROGRAM_KEY ProgramKey; + EFI_RPMB_READ_COUNTER ReadCounter; + EFI_RPMB_AUTHENTICATED_WRITE AuthenticatedWrite; + EFI_RPMB_AUTHENTICATED_READ AuthenticatedRead; +}; + +__inline__ +static +CONST CHAR16* +RpmbOperationResultToString ( + UINT16 OperationResult + ) +{ + switch (OperationResult) { + case EFI_RPMB_OK: + return L"Operation OK"; + case EFI_RPMB_ERROR_GENERAL: + return L"General failure"; + case EFI_RPMB_ERROR_AUTH: + return L"Authentication failure"; + case EFI_RPMB_ERROR_COUNTER: + return L"Counter failure"; + case EFI_RPMB_ERROR_ADDRESS: + return L"Address failure"; + case EFI_RPMB_ERROR_WRITE: + return L"Write failure"; + case EFI_RPMB_ERROR_READ: + return L"Read failure"; + case EFI_RPMB_ERROR_KEY: + return L"Authentication key not yet programmed"; + default: + return L"Undefined operation result"; + } +} + +extern EFI_GUID gEfiRpmbIoProtocolGuid; + +#endif // __RPMB_IO_H__ diff --git a/Platform/Microsoft/Include/Protocol/Sdhc.h b/Platform/Microsof= t/Include/Protocol/Sdhc.h new file mode 100644 index 000000000000..381cd823de0c --- /dev/null +++ b/Platform/Microsoft/Include/Protocol/Sdhc.h @@ -0,0 +1,197 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Copyright (c) 2011-2014, ARM Limited. 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_H__ +#define __SDHC_H__ + +// +// Global ID for the SDHC Protocol {46055B0F-992A-4AD7-8F81-148186FFDF72} +// +#define EFI_SDHC_PROTOCOL_GUID \ + { 0x46055b0f, 0x992a, 0x4ad7, { 0x8f, 0x81, 0x14, 0x81, 0x86, 0xff, 0x= df, 0x72 } }; + +typedef UINT16 SD_COMMAND_INDEX; + +typedef enum { + SdCommandTypeUndefined =3D 0, + SdCommandTypeSuspend, + SdCommandTypeResume, + SdCommandTypeAbort +} SD_COMMAND_TYPE; + +typedef enum { + SdCommandClassUndefined =3D 0, + SdCommandClassStandard, + SdCommandClassApp +} SD_COMMAND_CLASS; + +typedef enum { + SdResponseTypeUndefined =3D 0, + SdResponseTypeNone, + SdResponseTypeR1, + SdResponseTypeR1B, + SdResponseTypeR2, + SdResponseTypeR3, + SdResponseTypeR4, + SdResponseTypeR5, + SdResponseTypeR5B, + SdResponseTypeR6 +} SD_RESPONSE_TYPE; + +typedef enum { + SdTransferTypeUndefined =3D 0, + SdTransferTypeNone, + SdTransferTypeSingleBlock, + SdTransferTypeMultiBlock, + SdTransferTypeMultiBlockNoStop +} SD_TRANSFER_TYPE; + +typedef enum { + SdTransferDirectionUndefined =3D 0, + SdTransferDirectionRead, + SdTransferDirectionWrite +} SD_TRANSFER_DIRECTION; + +typedef struct { + SD_COMMAND_INDEX Index; + SD_COMMAND_TYPE Type; + SD_COMMAND_CLASS Class; + SD_RESPONSE_TYPE ResponseType; + SD_TRANSFER_TYPE TransferType; + SD_TRANSFER_DIRECTION TransferDirection; +} SD_COMMAND; + +typedef struct { + UINT32 BlockSize; + UINT32 BlockCount; + VOID* Buffer; +} SD_COMMAND_XFR_INFO; + +typedef enum { + SdBusWidthUndefined =3D 0, + SdBusWidth1Bit =3D 1, + SdBusWidth4Bit =3D 4, + SdBusWidth8Bit =3D 8 +} SD_BUS_WIDTH; + +typedef enum { + SdhcResetTypeUndefined =3D 0, + SdhcResetTypeAll, + SdhcResetTypeCmd, + SdhcResetTypeData +} SDHC_RESET_TYPE; + +typedef struct { + UINT32 MaximumBlockSize; + UINT32 MaximumBlockCount; +} SDHC_CAPABILITIES; +// +// Forward declaration for EFI_SDHC_PROTOCOL +// +typedef struct _EFI_SDHC_PROTOCOL EFI_SDHC_PROTOCOL; + +typedef VOID (EFIAPI *SDHC_GET_CAPABILITIES) ( + IN EFI_SDHC_PROTOCOL *This, + OUT SDHC_CAPABILITIES *Capabilities + ); + +typedef EFI_STATUS (EFIAPI *SDHC_SOFTWARERESET) ( + IN EFI_SDHC_PROTOCOL *This, + IN SDHC_RESET_TYPE ResetType + ); + +typedef EFI_STATUS (EFIAPI *SDHC_SETCLOCK) ( + IN EFI_SDHC_PROTOCOL *This, + IN UINT32 TargetFreqHz + ); + +typedef EFI_STATUS (EFIAPI *SDHC_SETBUSWIDTH) ( + IN EFI_SDHC_PROTOCOL *This, + IN SD_BUS_WIDTH BusWidth + ); + +typedef BOOLEAN (EFIAPI *SDHC_ISCARDPRESENT) ( + IN EFI_SDHC_PROTOCOL *This + ); + +typedef BOOLEAN (EFIAPI *SDHC_ISREADONLY) ( + IN EFI_SDHC_PROTOCOL *This + ); + +typedef EFI_STATUS (EFIAPI *SDHC_SENDCOMMAND) ( + IN EFI_SDHC_PROTOCOL *This, + IN const SD_COMMAND *Cmd, + IN UINT32 Argument, + IN OPTIONAL const SD_COMMAND_XFR_INFO *XfrInfo + ); + +typedef EFI_STATUS (EFIAPI *SDHC_RECEIVERESPONSE) ( + IN EFI_SDHC_PROTOCOL *This, + IN const SD_COMMAND *Cmd, + OUT UINT32 *Buffer + ); + +typedef EFI_STATUS (EFIAPI *SDHC_READBLOCKDATA) ( + IN EFI_SDHC_PROTOCOL *This, + IN UINTN LengthInBytes, + OUT UINT32 *Buffer + ); + +typedef EFI_STATUS (EFIAPI *SDHC_WRITEBLOCKDATA) ( + IN EFI_SDHC_PROTOCOL *This, + IN UINTN LengthInBytes, + IN const UINT32 *Buffer + ); + +typedef VOID (EFIAPI *SDHC_CLEANUP) ( + IN EFI_SDHC_PROTOCOL *This + ); + +struct _EFI_SDHC_PROTOCOL { + UINT32 Revision; + + // + // A unique ID that identify the SDHC device among other + // SDHC devices on the system + // + UINT32 SdhcId; + + // + // Context area allocated by the SDHC driver + // + VOID *PrivateContext; + + // + // SDHHC Callbacks + // + SDHC_GET_CAPABILITIES GetCapabilities; + SDHC_SOFTWARERESET SoftwareReset; + SDHC_SETCLOCK SetClock; + SDHC_SETBUSWIDTH SetBusWidth; + SDHC_ISCARDPRESENT IsCardPresent; + SDHC_ISREADONLY IsReadOnly; + SDHC_SENDCOMMAND SendCommand; + SDHC_RECEIVERESPONSE ReceiveResponse; + SDHC_READBLOCKDATA ReadBlockData; + SDHC_WRITEBLOCKDATA WriteBlockData; + SDHC_CLEANUP Cleanup; +}; + +#define SDHC_PROTOCOL_INTERFACE_REVISION 0x00010000 // 1.0 + +extern EFI_GUID gEfiSdhcProtocolGuid; + +#endif // __SDHC_H__ + --=20 2.16.2.gvfs.1.33.gf5370f1