From patchwork Wed Nov 23 13:36:21 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Haojian Zhuang X-Patchwork-Id: 83669 Delivered-To: patch@linaro.org Received: by 10.140.97.165 with SMTP id m34csp2639493qge; Wed, 23 Nov 2016 05:36:37 -0800 (PST) X-Received: by 10.99.253.85 with SMTP id m21mr5397333pgj.38.1479908197267; Wed, 23 Nov 2016 05:36:37 -0800 (PST) Return-Path: Received: from ml01.01.org (ml01.01.org. [2001:19d0:306:5::1]) by mx.google.com with ESMTPS id t27si33813082pfj.212.2016.11.23.05.36.36 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 23 Nov 2016 05:36:37 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) client-ip=2001:19d0:306:5::1; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dmarc=fail (p=NONE dis=NONE) header.from=linaro.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id E030081EA7; Wed, 23 Nov 2016 05:36:36 -0800 (PST) X-Original-To: edk2-devel@lists.01.org Delivered-To: edk2-devel@lists.01.org Received: from mail-pg0-x22a.google.com (mail-pg0-x22a.google.com [IPv6:2607:f8b0:400e:c05::22a]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 996D781EA7 for ; Wed, 23 Nov 2016 05:36:35 -0800 (PST) Received: by mail-pg0-x22a.google.com with SMTP id 3so6365382pgd.0 for ; Wed, 23 Nov 2016 05:36:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=zFmqnSCMbKJqWAZOA6suZ/usqJAsx2kf+TR3G8a4nkg=; b=JJFB+iPoiUPQaKIokUysjk1t2qFhMnDw/SFM6RBAbJVM7qk1C3fsQlAHETHSk5YnKP TBmkOsCUwE+I89YktiNwUllp+OP10tJ+okogfD8MFVMD/IgkouriMO14vBbGG5/J/jrI /jkWYJzkWA24I87lfVwtuUjN2f2GZrAX4wt/E= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=zFmqnSCMbKJqWAZOA6suZ/usqJAsx2kf+TR3G8a4nkg=; b=EguMdXG2vpjMjobAnHSOxGS+SFa9HqUDbhuyru7Hc/NaZ+tPHyOe74giLf9uTAzHTu RWZmMBZ0422Itxed8HaobKC6gu1ChYoGqguwzlRZZoTC69nOHvOo0NwbOtZquYxAaKVG YPWn8gK//Ldu1DPghcd14Q+YTAKS7/kSs7Vsp++FUVXA0Cc+bUrB3zyjMqGPGWSilLRO 7AmeYA6hE5sO62eDF6Us0kay4+R2zP/xK7vQrE44nMhA0jXT00NfHCxWWDJRKIJPhePW Khs0sRNCHEKQuP8Wvu1hSKEfgTppKcvt72v9O7dUlg8xDn4B0GZZeey/Qs7facoXT+OR uPXg== X-Gm-Message-State: AKaTC0149W/IHjtXE3A1UtMCZpwKOP4YAYglMFohMbF9IGjJ0O/jHa7p647fcFWktmng4FgY X-Received: by 10.84.210.130 with SMTP id a2mr6790510pli.106.1479908195195; Wed, 23 Nov 2016 05:36:35 -0800 (PST) Received: from localhost.localdomain ([45.56.159.99]) by smtp.gmail.com with ESMTPSA id t184sm35126910pgt.36.2016.11.23.05.36.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 23 Nov 2016 05:36:34 -0800 (PST) From: Haojian Zhuang To: ryan.harkin@linaro.org, edk2-devel@lists.01.org, leif.lindholm@linaro.org, ard.biesheuvel@linaro.org Date: Wed, 23 Nov 2016 21:36:21 +0800 Message-Id: <1479908184-9406-2-git-send-email-haojian.zhuang@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1479908184-9406-1-git-send-email-haojian.zhuang@linaro.org> References: <1479908184-9406-1-git-send-email-haojian.zhuang@linaro.org> Subject: [edk2] [PATCH v8 1/4] MmcDxe: add interface in mmc host protocol X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Haojian Zhuang MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" Add the interface to change the bus width, speed and check multi blocks. By default, MMC is initialized with 1-bit mode and less than 400KHz bus clock. It causes MMC working inefficiently. Set io bus width on both MMC controller and EXTCSD. Otherwise, it may cause unmatched failure case. And support more timing mode, high speed, HS200 & HS400 mode. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Haojian Zhuang Tested-by: Ryan Harkin --- EmbeddedPkg/Include/Protocol/MmcHost.h | 31 +++- EmbeddedPkg/Universal/MmcDxe/Mmc.h | 5 + EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c | 185 ++++++++++++++++++++++- 3 files changed, 217 insertions(+), 4 deletions(-) -- 2.7.4 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel diff --git a/EmbeddedPkg/Include/Protocol/MmcHost.h b/EmbeddedPkg/Include/Protocol/MmcHost.h index 89f2e80..4f0a7b4 100644 --- a/EmbeddedPkg/Include/Protocol/MmcHost.h +++ b/EmbeddedPkg/Include/Protocol/MmcHost.h @@ -49,6 +49,7 @@ typedef UINT32 MMC_CMD; #define MMC_CMD2 (MMC_INDX(2) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_LONG_RESPONSE) #define MMC_CMD3 (MMC_INDX(3) | MMC_CMD_WAIT_RESPONSE) #define MMC_CMD5 (MMC_INDX(5) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_NO_CRC_RESPONSE) +#define MMC_CMD6 (MMC_INDX(6) | MMC_CMD_WAIT_RESPONSE) #define MMC_CMD7 (MMC_INDX(7) | MMC_CMD_WAIT_RESPONSE) #define MMC_CMD8 (MMC_INDX(8) | MMC_CMD_WAIT_RESPONSE) #define MMC_CMD9 (MMC_INDX(9) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_LONG_RESPONSE) @@ -82,6 +83,16 @@ typedef enum _MMC_STATE { MmcDisconnectState, } MMC_STATE; +#define EMMCBACKWARD (0) +#define EMMCHS26 (1 << 0) // High-Speed @26MHz at rated device voltages +#define EMMCHS52 (1 << 1) // High-Speed @52MHz at rated device voltages +#define EMMCHS52DDR1V8 (1 << 2) // High-Speed Dual Data Rate @52MHz 1.8V or 3V I/O +#define EMMCHS52DDR1V2 (1 << 3) // High-Speed Dual Data Rate @52MHz 1.2V I/O +#define EMMCHS200SDR1V8 (1 << 4) // HS200 Single Data Rate @200MHz 1.8V I/O +#define EMMCHS200SDR1V2 (1 << 5) // HS200 Single Data Rate @200MHz 1.2V I/O +#define EMMCHS400DDR1V8 (1 << 6) // HS400 Dual Data Rate @400MHz 1.8V I/O +#define EMMCHS400DDR1V2 (1 << 7) // HS400 Dual Data Rate @400MHz 1.2V I/O + /// /// Forward declaration for EFI_MMC_HOST_PROTOCOL /// @@ -131,6 +142,16 @@ typedef EFI_STATUS (EFIAPI *MMC_WRITEBLOCKDATA) ( IN UINT32 *Buffer ); +typedef EFI_STATUS (EFIAPI *MMC_SETIOS) ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN UINT32 BusClockFreq, + IN UINT32 BusWidth, + IN UINT32 TimingMode + ); + +typedef BOOLEAN (EFIAPI *MMC_ISMULTIBLOCK) ( + IN EFI_MMC_HOST_PROTOCOL *This + ); struct _EFI_MMC_HOST_PROTOCOL { @@ -147,9 +168,17 @@ struct _EFI_MMC_HOST_PROTOCOL { MMC_READBLOCKDATA ReadBlockData; MMC_WRITEBLOCKDATA WriteBlockData; + MMC_SETIOS SetIos; + MMC_ISMULTIBLOCK IsMultiBlock; + }; -#define MMC_HOST_PROTOCOL_REVISION 0x00010001 // 1.1 +#define MMC_HOST_PROTOCOL_REVISION 0x00010002 // 1.2 + +#define MMC_HOST_HAS_SETIOS(Host) (Host->Revision >= MMC_HOST_PROTOCOL_REVISION && \ + Host->SetIos != NULL) +#define MMC_HOST_HAS_ISMULTIBLOCK(Host) (Host->Revision >= MMC_HOST_PROTOCOL_REVISION && \ + Host->IsMultiBlock != NULL) extern EFI_GUID gEfiMmcHostProtocolGuid; diff --git a/EmbeddedPkg/Universal/MmcDxe/Mmc.h b/EmbeddedPkg/Universal/MmcDxe/Mmc.h index 112bc47..fb3f6c9 100644 --- a/EmbeddedPkg/Universal/MmcDxe/Mmc.h +++ b/EmbeddedPkg/Universal/MmcDxe/Mmc.h @@ -55,6 +55,11 @@ #define MMC_R0_STATE_TRAN 4 #define MMC_R0_STATE_DATA 5 +#define EMMC_CMD6_ARG_ACCESS(x) (((x) & 0x3) << 24) +#define EMMC_CMD6_ARG_INDEX(x) (((x) & 0xFF) << 16) +#define EMMC_CMD6_ARG_VALUE(x) (((x) & 0xFF) << 8) +#define EMMC_CMD6_ARG_CMD_SET(x) (((x) & 0x7) << 0) + typedef enum { UNKNOWN_CARD, MMC_CARD, //MMC card diff --git a/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c b/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c index 9aefb26..7441459 100644 --- a/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c +++ b/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c @@ -25,11 +25,111 @@ typedef union { #define EMMC_CARD_SIZE 512 #define EMMC_ECSD_SIZE_OFFSET 53 +#define EXTCSD_BUS_WIDTH 183 +#define EXTCSD_HS_TIMING 185 + +#define EMMC_TIMING_BACKWARD 0 +#define EMMC_TIMING_HS 1 +#define EMMC_TIMING_HS200 2 +#define EMMC_TIMING_HS400 3 + +#define EMMC_BUS_WIDTH_1BIT 0 +#define EMMC_BUS_WIDTH_4BIT 1 +#define EMMC_BUS_WIDTH_8BIT 2 +#define EMMC_BUS_WIDTH_DDR_4BIT 5 +#define EMMC_BUS_WIDTH_DDR_8BIT 6 + +#define EMMC_SWITCH_ERROR (1 << 7) + +#define DEVICE_STATE(x) (((x) >> 9) & 0xf) +typedef enum _EMMC_DEVICE_STATE { + EMMC_IDLE_STATE = 0, + EMMC_READY_STATE, + EMMC_IDENT_STATE, + EMMC_STBY_STATE, + EMMC_TRAN_STATE, + EMMC_DATA_STATE, + EMMC_RCV_STATE, + EMMC_PRG_STATE, + EMMC_DIS_STATE, + EMMC_BTST_STATE, + EMMC_SLP_STATE +} EMMC_DEVICE_STATE; + UINT32 mEmmcRcaCount = 0; STATIC EFI_STATUS EFIAPI +EmmcGetDeviceState ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + OUT EMMC_DEVICE_STATE *State + ) +{ + EFI_MMC_HOST_PROTOCOL *Host; + EFI_STATUS Status; + UINT32 Data, RCA; + + if (State == NULL) { + return EFI_INVALID_PARAMETER; + } + + Host = MmcHostInstance->MmcHost; + RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET; + Status = Host->SendCommand (Host, MMC_CMD13, RCA); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to get card status, Status=%r.\n", Status)); + return Status; + } + Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R1, &Data); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to get response of CMD13, Status=%r.\n", Status)); + return Status; + } + if (Data & EMMC_SWITCH_ERROR) { + DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to switch expected mode, Status=%r.\n", Status)); + return EFI_DEVICE_ERROR; + } + *State = DEVICE_STATE(Data); + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +EmmcSetEXTCSD ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + UINT32 ExtCmdIndex, + UINT32 Value + ) +{ + EFI_MMC_HOST_PROTOCOL *Host; + EMMC_DEVICE_STATE State; + EFI_STATUS Status; + UINT32 Argument; + + Host = MmcHostInstance->MmcHost; + Argument = EMMC_CMD6_ARG_ACCESS(3) | EMMC_CMD6_ARG_INDEX(ExtCmdIndex) | + EMMC_CMD6_ARG_VALUE(Value) | EMMC_CMD6_ARG_CMD_SET(1); + Status = Host->SendCommand (Host, MMC_CMD6, Argument); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcSetEXTCSD(): Failed to send CMD6, Status=%r.\n", Status)); + return Status; + } + // Make sure device exiting prog mode + do { + Status = EmmcGetDeviceState (MmcHostInstance, &State); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcSetEXTCSD(): Failed to get device state, Status=%r.\n", Status)); + return Status; + } + } while (State == EMMC_PRG_STATE); + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI EmmcIdentificationMode ( IN MMC_HOST_INSTANCE *MmcHostInstance, IN OCR_RESPONSE Response @@ -38,6 +138,7 @@ EmmcIdentificationMode ( EFI_MMC_HOST_PROTOCOL *Host; EFI_BLOCK_IO_MEDIA *Media; EFI_STATUS Status; + EMMC_DEVICE_STATE State; UINT32 RCA; Host = MmcHostInstance->MmcHost; @@ -84,6 +185,22 @@ EmmcIdentificationMode ( DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Card selection error, Status=%r.\n", Status)); } + if (MMC_HOST_HAS_SETIOS(Host)) { + // Set 1-bit bus width + Status = Host->SetIos (Host, 0, 1, EMMCBACKWARD); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set 1-bit bus width error, Status=%r.\n", Status)); + return Status; + } + + // Set 1-bit bus width for EXTCSD + Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, EMMC_BUS_WIDTH_1BIT); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set extcsd bus width error, Status=%r.\n", Status)); + return Status; + } + } + // Fetch ECSD Status = Host->SendCommand (Host, MMC_CMD8, RCA); if (EFI_ERROR (Status)) { @@ -96,6 +213,15 @@ EmmcIdentificationMode ( return Status; } + // Make sure device exiting data mode + do { + Status = EmmcGetDeviceState (MmcHostInstance, &State); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to get device state, Status=%r.\n", Status)); + return Status; + } + } while (State == EMMC_DATA_STATE); + // Set up media Media->BlockSize = EMMC_CARD_SIZE; // 512-byte support is mandatory for eMMC cards Media->MediaId = MmcHostInstance->CardInfo.CIDData.PSN; @@ -113,6 +239,57 @@ EmmcIdentificationMode ( STATIC EFI_STATUS +InitializeEmmcDevice ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + EFI_MMC_HOST_PROTOCOL *Host; + EFI_STATUS Status = EFI_SUCCESS; + ECSD *ECSDData; + UINT32 BusClockFreq, Idx; + UINT32 TimingMode[4] = {EMMCHS52DDR1V2, EMMCHS52DDR1V8, EMMCHS52, EMMCHS26}; + + Host = MmcHostInstance->MmcHost; + ECSDData = &MmcHostInstance->CardInfo.ECSDData; + if (ECSDData->DEVICE_TYPE == EMMCBACKWARD) + return EFI_SUCCESS; + + if (!MMC_HOST_HAS_SETIOS(Host)) { + return EFI_SUCCESS; + } + Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_HS_TIMING, EMMC_TIMING_HS); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to switch high speed mode, Status:%r.\n", Status)); + return Status; + } + + for (Idx = 0; Idx < 4; Idx++) { + switch (TimingMode[Idx]) { + case EMMCHS52DDR1V2: + case EMMCHS52DDR1V8: + case EMMCHS52: + BusClockFreq = 52000000; + break; + case EMMCHS26: + BusClockFreq = 26000000; + break; + default: + return EFI_UNSUPPORTED; + } + Status = Host->SetIos (Host, BusClockFreq, 8, TimingMode[Idx]); + if (!EFI_ERROR (Status)) { + Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, EMMC_BUS_WIDTH_DDR_8BIT); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to set EXTCSD bus width, Status:%r\n", Status)); + } + return Status; + } + } + return Status; +} + +STATIC +EFI_STATUS InitializeSdMmcDevice ( IN MMC_HOST_INSTANCE *MmcHostInstance ) @@ -431,9 +608,11 @@ InitializeMmcDevice ( if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) { Status = InitializeSdMmcDevice (MmcHostInstance); - if (EFI_ERROR (Status)) { - return Status; - } + } else { + Status = InitializeEmmcDevice (MmcHostInstance); + } + if (EFI_ERROR (Status)) { + return Status; } // Set Block Length