From patchwork Fri Feb 26 09:27:53 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Haojian Zhuang X-Patchwork-Id: 62977 Delivered-To: patch@linaro.org Received: by 10.112.199.169 with SMTP id jl9csp608615lbc; Fri, 26 Feb 2016 01:28:42 -0800 (PST) X-Received: by 10.98.66.138 with SMTP id h10mr639260pfd.89.1456478922309; Fri, 26 Feb 2016 01:28:42 -0800 (PST) Return-Path: Received: from ml01.01.org (ml01.01.org. [198.145.21.10]) by mx.google.com with ESMTPS id m21si18751651pfi.245.2016.02.26.01.28.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 26 Feb 2016 01:28:42 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) client-ip=198.145.21.10; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dkim=neutral (body hash did not verify) header.i=@linaro.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id AE5AB1A1E1C; Fri, 26 Feb 2016 01:28:46 -0800 (PST) X-Original-To: edk2-devel@lists.01.org Delivered-To: edk2-devel@lists.01.org Received: from mail-pf0-x234.google.com (mail-pf0-x234.google.com [IPv6:2607:f8b0:400e:c00::234]) (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 265FE1A1E0D for ; Fri, 26 Feb 2016 01:28:45 -0800 (PST) Received: by mail-pf0-x234.google.com with SMTP id e127so49425217pfe.3 for ; Fri, 26 Feb 2016 01:28:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=message-id:from:to:cc:subject:date:in-reply-to:references :mime-version; bh=HtK5QUksVJMPOp78YXQZiVbHqIc37GdAq6EtMKBRRFs=; b=PeEEFEbzPu8bC/yDgnZLzLLuEIBLaXwW39eqMltHBHiyGR3tj8QsRxp8O4WCJWQWy/ 3pFr9XqnrEoNy/ooMG/puO3IJu9La9O/KL6Y0mhxUy+6A/K3aNbOErC7Wn/Tx6+OOJaq tSXNhs9+esCSOqAvTMHCBOGzK7Gmhoz+VY4z0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:message-id:from:to:cc:subject:date:in-reply-to :references:mime-version; bh=HtK5QUksVJMPOp78YXQZiVbHqIc37GdAq6EtMKBRRFs=; b=TfqPZVrTo+TB1dx4iYagwEEJJYaURsA0S/EZHC9WIssf6vQmdLLT1g0YjP/Yv8c+wh xSH7zkBAyVgod1A4NBckarvoxRdymxp4J/ssQU5/gvnHEDRjoWJ3Zkmjg3zaQZCFlLkO alYlF5a8cbzaf0QnTDW8KEK1df7Bc3uFmMF5avSdaedDop/67LPC+76L3Sqf+wh5Kx8W /pGu0oSf6nkMY+do6L0kgmEgybqVwb7YoveytvHKHW7Rzd3+EPFd3fLXbo5K1VeX7ZTv HwWO/HD2cv6P0h1eS7BWJQnDqnlkOHVEYza+HsTgJ1DG06NETputpmikiuMZHWTSYt11 I62A== X-Gm-Message-State: AD7BkJKrtbdpBbMgbWClmmYm+eIS7RwAlPS3bQGMECN5DfFo2F7HfTE1Mann8/occOkkPQXS X-Received: by 10.98.16.198 with SMTP id 67mr647150pfq.21.1456478920017; Fri, 26 Feb 2016 01:28:40 -0800 (PST) Received: from mail.hotmail.com (blu004-wss1s3.hotmail.com. [134.170.2.218]) by smtp.gmail.com with ESMTPSA id g74sm17860777pfj.1.2016.02.26.01.28.38 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 26 Feb 2016 01:28:38 -0800 (PST) Received: from BLU437-SMTP102 ([134.170.2.215]) by BLU004-WSS1S3.hotmail.com over TLS secured channel with Microsoft SMTPSVC(7.5.7601.23008); Fri, 26 Feb 2016 01:28:37 -0800 X-TMN: [HKwPs/Po5oZZ0bBrRW8mvRlGKY9/PA7S] Message-ID: From: Haojian Zhuang To: edk2-devel@lists.01.org, leif.lindholm@linaro.org, ard.biesheuvel@linaro.org Date: Fri, 26 Feb 2016 17:27:53 +0800 X-Mailer: git-send-email 1.9.1 In-Reply-To: <1456478876-23434-1-git-send-email-haojian.zhuang@linaro.org> References: <1456478876-23434-1-git-send-email-haojian.zhuang@linaro.org> X-OriginalArrivalTime: 26 Feb 2016 09:28:35.0398 (UTC) FILETIME=[10FEDE60:01D17078] MIME-Version: 1.0 Cc: Haojian Zhuang Subject: [edk2] [PATCH 6/9] MmcDxe: set io bus width before reading EXTCSD X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" 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 --- EmbeddedPkg/Include/Protocol/MmcHost.h | 16 +- EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c | 225 +++++++++++++++++++++-- 2 files changed, 219 insertions(+), 22 deletions(-) -- 1.9.1 _______________________________________________ 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 13e99e7..5e3a2b7 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 /// @@ -133,8 +144,9 @@ typedef EFI_STATUS (EFIAPI *MMC_WRITEBLOCKDATA) ( typedef EFI_STATUS (EFIAPI *MMC_SETIOS) ( IN EFI_MMC_HOST_PROTOCOL *This, - IN UINT32 BusClockRate, - IN UINT32 BusWidth + IN UINT32 BusClockFreq, + IN UINT32 BusWidth, + IN UINT32 TimingMode ); diff --git a/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c b/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c index 5be3d86..a5915e4 100644 --- a/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c +++ b/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c @@ -25,11 +25,109 @@ 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 = (3 << 24) | ((ExtCmdIndex & 0xff) << 16) | ((Value & 0xff) << 8) | 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 @@ -37,6 +135,7 @@ EmmcIdentificationMode ( { EFI_MMC_HOST_PROTOCOL *Host; EFI_BLOCK_IO_MEDIA *Media; + EMMC_DEVICE_STATE State; EFI_STATUS Status; UINT32 RCA; @@ -84,35 +183,117 @@ EmmcIdentificationMode ( DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Card selection error, Status=%r.\n", Status)); } - // Fetch ECSD - Status = Host->SendCommand (Host, MMC_CMD8, RCA); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD fetch error, Status=%r.\n", Status)); - } + // MMC v4 specific + if (MmcHostInstance->CardInfo.CSDData.SPEC_VERS == 4) { + if (Host->SetIos) { + // 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; + } - Status = Host->ReadBlockData (Host, 0, 512, (UINT32 *)&(MmcHostInstance->CardInfo.ECSDData)); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD read 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)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD fetch error, Status=%r.\n", Status)); + } + Status = Host->ReadBlockData (Host, 0, 512, (UINT32 *)&(MmcHostInstance->CardInfo.ECSDData)); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD read error, Status=%r.\n", Status)); + 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); + + // Compute last block using bits [215:212] of the ECSD + Media->LastBlock = MmcHostInstance->CardInfo.ECSDData.SEC_COUNT - 1; // eMMC isn't supposed to report this for + // Cards <2GB in size, but the model does. + + // Setup card type + MmcHostInstance->CardInfo.CardType = EMMC_CARD; + } // Set up media Media->BlockSize = EMMC_CARD_SIZE; // 512-byte support is mandatory for eMMC cards Media->MediaId = MmcHostInstance->CardInfo.CIDData.PSN; Media->ReadOnly = MmcHostInstance->CardInfo.CSDData.PERM_WRITE_PROTECT; Media->LogicalBlocksPerPhysicalBlock = 1; Media->IoAlign = 4; - // Compute last block using bits [215:212] of the ECSD - Media->LastBlock = MmcHostInstance->CardInfo.ECSDData.SEC_COUNT - 1; // eMMC isn't supposed to report this for - // Cards <2GB in size, but the model does. - - // Setup card type - MmcHostInstance->CardInfo.CardType = EMMC_CARD; return EFI_SUCCESS; } STATIC EFI_STATUS +InitializeEmmcDevice ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + EFI_MMC_HOST_PROTOCOL *Host; + EFI_STATUS Status = EFI_SUCCESS; + ECSD *ECSDData; + BOOLEAN Found = FALSE; + UINT32 BusClockFreq, Idx; + UINT32 TimingMode[4] = {EMMCHS52DDR1V2, EMMCHS52DDR1V8, EMMCHS52, EMMCHS26}; + + Host = MmcHostInstance->MmcHost; + if (MmcHostInstance->CardInfo.CSDData.SPEC_VERS < 4) + return EFI_SUCCESS; + ECSDData = &MmcHostInstance->CardInfo.ECSDData; + if (ECSDData->DEVICE_TYPE == EMMCBACKWARD) + return EFI_SUCCESS; + + if (Host->SetIos) { + 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)) { + Found = TRUE; + break; + } + } + if (Found) { + 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; +} + +STATIC +EFI_STATUS InitializeSdMmcDevice ( IN MMC_HOST_INSTANCE *MmcHostInstance ) @@ -429,11 +610,15 @@ InitializeMmcDevice ( return Status; } - if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) { - Status = InitializeSdMmcDevice (MmcHostInstance); - if (EFI_ERROR (Status)) { - return Status; + if (MmcHostInstance->CardInfo.CardType == EMMC_CARD) { + if (MmcHost->SetIos) { + Status = InitializeEmmcDevice (MmcHostInstance); } + } else { + Status = InitializeSdMmcDevice (MmcHostInstance); + } + if (EFI_ERROR (Status)) { + return Status; } // Set Block Length