1b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin/** @file 2b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin* 3eff98cf9daf7353274f958bea570f0da419a09a5Olivier Martin* Copyright (c) 2011-2015, ARM Limited. All rights reserved. 4b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin* 5b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin* This program and the accompanying materials 6b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin* are licensed and made available under the terms and conditions of the BSD License 7b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin* which accompanies this distribution. The full text of the license may be found at 8b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin* http://opensource.org/licenses/bsd-license.php 9b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin* 10b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin* 13b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin**/ 14b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 15e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang#include <Library/BaseMemoryLib.h> 16e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang#include <Library/TimerLib.h> 17e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang 18b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin#include "Mmc.h" 19b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 20b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martintypedef union { 21b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin UINT32 Raw; 22b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin OCR Ocr; 23b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin} OCR_RESPONSE; 24b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 25b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin#define MAX_RETRY_COUNT 1000 26b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin#define CMD_RETRY_COUNT 20 27b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin#define RCA_SHIFT_OFFSET 16 28b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin#define EMMC_CARD_SIZE 512 29b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin#define EMMC_ECSD_SIZE_OFFSET 53 30b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 31752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang#define EXTCSD_BUS_WIDTH 183 32752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang#define EXTCSD_HS_TIMING 185 33752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 34752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang#define EMMC_TIMING_BACKWARD 0 35752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang#define EMMC_TIMING_HS 1 36752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang#define EMMC_TIMING_HS200 2 37752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang#define EMMC_TIMING_HS400 3 38752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 39752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang#define EMMC_BUS_WIDTH_1BIT 0 40752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang#define EMMC_BUS_WIDTH_4BIT 1 41752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang#define EMMC_BUS_WIDTH_8BIT 2 42752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang#define EMMC_BUS_WIDTH_DDR_4BIT 5 43752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang#define EMMC_BUS_WIDTH_DDR_8BIT 6 44752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 45752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang#define EMMC_SWITCH_ERROR (1 << 7) 46752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 47e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang#define SD_BUS_WIDTH_1BIT (1 << 0) 48e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang#define SD_BUS_WIDTH_4BIT (1 << 2) 49e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang 50e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang#define SD_CCC_SWITCH (1 << 10) 51e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang 52752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang#define DEVICE_STATE(x) (((x) >> 9) & 0xf) 53752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuangtypedef enum _EMMC_DEVICE_STATE { 54752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EMMC_IDLE_STATE = 0, 55752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EMMC_READY_STATE, 56752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EMMC_IDENT_STATE, 57752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EMMC_STBY_STATE, 58752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EMMC_TRAN_STATE, 59752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EMMC_DATA_STATE, 60752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EMMC_RCV_STATE, 61752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EMMC_PRG_STATE, 62752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EMMC_DIS_STATE, 63752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EMMC_BTST_STATE, 64752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EMMC_SLP_STATE 65752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang} EMMC_DEVICE_STATE; 66752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 67b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier MartinUINT32 mEmmcRcaCount = 0; 68b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 69b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier MartinSTATIC 70b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier MartinEFI_STATUS 71b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier MartinEFIAPI 72752ae80514ccb3532a6d6d16a122642573eabdeeHaojian ZhuangEmmcGetDeviceState ( 73752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang IN MMC_HOST_INSTANCE *MmcHostInstance, 74752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang OUT EMMC_DEVICE_STATE *State 75752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang ) 76752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang{ 77752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EFI_MMC_HOST_PROTOCOL *Host; 78752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EFI_STATUS Status; 79752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang UINT32 Data, RCA; 80752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 81752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang if (State == NULL) { 82752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return EFI_INVALID_PARAMETER; 83752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 84752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 85752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang Host = MmcHostInstance->MmcHost; 86752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET; 87752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang Status = Host->SendCommand (Host, MMC_CMD13, RCA); 88752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang if (EFI_ERROR (Status)) { 89752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to get card status, Status=%r.\n", Status)); 90752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return Status; 91752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 92752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R1, &Data); 93752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang if (EFI_ERROR (Status)) { 94752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to get response of CMD13, Status=%r.\n", Status)); 95752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return Status; 96752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 97752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang if (Data & EMMC_SWITCH_ERROR) { 98752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to switch expected mode, Status=%r.\n", Status)); 99752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return EFI_DEVICE_ERROR; 100752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 101752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang *State = DEVICE_STATE(Data); 102752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return EFI_SUCCESS; 103752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang} 104752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 105752ae80514ccb3532a6d6d16a122642573eabdeeHaojian ZhuangSTATIC 106752ae80514ccb3532a6d6d16a122642573eabdeeHaojian ZhuangEFI_STATUS 107752ae80514ccb3532a6d6d16a122642573eabdeeHaojian ZhuangEFIAPI 108752ae80514ccb3532a6d6d16a122642573eabdeeHaojian ZhuangEmmcSetEXTCSD ( 109752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang IN MMC_HOST_INSTANCE *MmcHostInstance, 110752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang UINT32 ExtCmdIndex, 111752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang UINT32 Value 112752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang ) 113752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang{ 114752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EFI_MMC_HOST_PROTOCOL *Host; 115752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EMMC_DEVICE_STATE State; 116752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EFI_STATUS Status; 117752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang UINT32 Argument; 118752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 119752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang Host = MmcHostInstance->MmcHost; 120752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang Argument = EMMC_CMD6_ARG_ACCESS(3) | EMMC_CMD6_ARG_INDEX(ExtCmdIndex) | 121752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EMMC_CMD6_ARG_VALUE(Value) | EMMC_CMD6_ARG_CMD_SET(1); 122752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang Status = Host->SendCommand (Host, MMC_CMD6, Argument); 123752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang if (EFI_ERROR (Status)) { 124752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang DEBUG ((EFI_D_ERROR, "EmmcSetEXTCSD(): Failed to send CMD6, Status=%r.\n", Status)); 125752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return Status; 126752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 127752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang // Make sure device exiting prog mode 128752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang do { 129752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang Status = EmmcGetDeviceState (MmcHostInstance, &State); 130752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang if (EFI_ERROR (Status)) { 131752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang DEBUG ((EFI_D_ERROR, "EmmcSetEXTCSD(): Failed to get device state, Status=%r.\n", Status)); 132752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return Status; 133752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 134752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } while (State == EMMC_PRG_STATE); 135752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return EFI_SUCCESS; 136752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang} 137752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 138752ae80514ccb3532a6d6d16a122642573eabdeeHaojian ZhuangSTATIC 139752ae80514ccb3532a6d6d16a122642573eabdeeHaojian ZhuangEFI_STATUS 140752ae80514ccb3532a6d6d16a122642573eabdeeHaojian ZhuangEFIAPI 141b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier MartinEmmcIdentificationMode ( 142b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin IN MMC_HOST_INSTANCE *MmcHostInstance, 143b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin IN OCR_RESPONSE Response 144b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin ) 145b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin{ 146b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin EFI_MMC_HOST_PROTOCOL *Host; 147b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin EFI_BLOCK_IO_MEDIA *Media; 148b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin EFI_STATUS Status; 149752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EMMC_DEVICE_STATE State; 150b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin UINT32 RCA; 151b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 152b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Host = MmcHostInstance->MmcHost; 153b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Media = MmcHostInstance->BlockIo.Media; 154b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 155b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Fetch card identity register 156b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = Host->SendCommand (Host, MMC_CMD2, 0); 157b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 158b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to send CMD2, Status=%r.\n", Status)); 159b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 160b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 161b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 162b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CIDData)); 163b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 164b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): CID retrieval error, Status=%r.\n", Status)); 165b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 166b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 167b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 168b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Assign a relative address value to the card 169b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHostInstance->CardInfo.RCA = ++mEmmcRcaCount; // TODO: might need a more sophisticated way of doing this 170b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET; 171b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = Host->SendCommand (Host, MMC_CMD3, RCA); 172b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 173b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): RCA set error, Status=%r.\n", Status)); 174b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 175b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 176b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 177b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Fetch card specific data 178b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = Host->SendCommand (Host, MMC_CMD9, RCA); 179b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 180b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to send CMD9, Status=%r.\n", Status)); 181b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 182b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 183b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 184b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CSDData)); 185b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 186b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): CSD retrieval error, Status=%r.\n", Status)); 187b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 188b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 189b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 190b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Select the card 191b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = Host->SendCommand (Host, MMC_CMD7, RCA); 192b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 193b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Card selection error, Status=%r.\n", Status)); 194b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 195b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 196752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang if (MMC_HOST_HAS_SETIOS(Host)) { 197752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang // Set 1-bit bus width 198752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang Status = Host->SetIos (Host, 0, 1, EMMCBACKWARD); 199752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang if (EFI_ERROR (Status)) { 200752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set 1-bit bus width error, Status=%r.\n", Status)); 201752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return Status; 202752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 203752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 204752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang // Set 1-bit bus width for EXTCSD 205752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, EMMC_BUS_WIDTH_1BIT); 206752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang if (EFI_ERROR (Status)) { 207752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set extcsd bus width error, Status=%r.\n", Status)); 208752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return Status; 209752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 210752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 211752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 212b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Fetch ECSD 213b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = Host->SendCommand (Host, MMC_CMD8, RCA); 214b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 215b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD fetch error, Status=%r.\n", Status)); 216b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 217b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 218e88fcb47c12ac3e21eb6efd9a39f9834c1ba28d3Haojian Zhuang Status = Host->ReadBlockData (Host, 0, 512, (UINT32 *)&(MmcHostInstance->CardInfo.ECSDData)); 219b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 220b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD read error, Status=%r.\n", Status)); 221b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 222b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 223b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 224752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang // Make sure device exiting data mode 225752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang do { 226752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang Status = EmmcGetDeviceState (MmcHostInstance, &State); 227752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang if (EFI_ERROR (Status)) { 228752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to get device state, Status=%r.\n", Status)); 229752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return Status; 230752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 231752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } while (State == EMMC_DATA_STATE); 232752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 233b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Set up media 234b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Media->BlockSize = EMMC_CARD_SIZE; // 512-byte support is mandatory for eMMC cards 235b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Media->MediaId = MmcHostInstance->CardInfo.CIDData.PSN; 236b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Media->ReadOnly = MmcHostInstance->CardInfo.CSDData.PERM_WRITE_PROTECT; 237b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Media->LogicalBlocksPerPhysicalBlock = 1; 238b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Media->IoAlign = 4; 239b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Compute last block using bits [215:212] of the ECSD 240e88fcb47c12ac3e21eb6efd9a39f9834c1ba28d3Haojian Zhuang Media->LastBlock = MmcHostInstance->CardInfo.ECSDData.SECTOR_COUNT - 1; // eMMC isn't supposed to report this for 241b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Cards <2GB in size, but the model does. 242b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 243b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Setup card type 244b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHostInstance->CardInfo.CardType = EMMC_CARD; 245b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return EFI_SUCCESS; 246b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin} 247b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 248b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier MartinSTATIC 249b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier MartinEFI_STATUS 250752ae80514ccb3532a6d6d16a122642573eabdeeHaojian ZhuangInitializeEmmcDevice ( 251752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang IN MMC_HOST_INSTANCE *MmcHostInstance 252752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang ) 253752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang{ 254752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EFI_MMC_HOST_PROTOCOL *Host; 255752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang EFI_STATUS Status = EFI_SUCCESS; 256752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang ECSD *ECSDData; 257752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang UINT32 BusClockFreq, Idx; 258752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang UINT32 TimingMode[4] = {EMMCHS52DDR1V2, EMMCHS52DDR1V8, EMMCHS52, EMMCHS26}; 259752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 260752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang Host = MmcHostInstance->MmcHost; 261752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang ECSDData = &MmcHostInstance->CardInfo.ECSDData; 262752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang if (ECSDData->DEVICE_TYPE == EMMCBACKWARD) 263752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return EFI_SUCCESS; 264752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 265752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang if (!MMC_HOST_HAS_SETIOS(Host)) { 266752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return EFI_SUCCESS; 267752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 268752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_HS_TIMING, EMMC_TIMING_HS); 269752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang if (EFI_ERROR (Status)) { 270752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to switch high speed mode, Status:%r.\n", Status)); 271752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return Status; 272752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 273752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 274752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang for (Idx = 0; Idx < 4; Idx++) { 275752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang switch (TimingMode[Idx]) { 276752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang case EMMCHS52DDR1V2: 277752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang case EMMCHS52DDR1V8: 278752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang case EMMCHS52: 279752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang BusClockFreq = 52000000; 280752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang break; 281752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang case EMMCHS26: 282752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang BusClockFreq = 26000000; 283752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang break; 284752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang default: 285752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return EFI_UNSUPPORTED; 286752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 287752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang Status = Host->SetIos (Host, BusClockFreq, 8, TimingMode[Idx]); 288752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang if (!EFI_ERROR (Status)) { 289752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, EMMC_BUS_WIDTH_DDR_8BIT); 290752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang if (EFI_ERROR (Status)) { 291752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to set EXTCSD bus width, Status:%r\n", Status)); 292752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 293752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return Status; 294752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 295752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 296752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return Status; 297752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang} 298752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang 299752ae80514ccb3532a6d6d16a122642573eabdeeHaojian ZhuangSTATIC 300752ae80514ccb3532a6d6d16a122642573eabdeeHaojian ZhuangEFI_STATUS 301b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier MartinInitializeSdMmcDevice ( 302b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin IN MMC_HOST_INSTANCE *MmcHostInstance 303b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin ) 304b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin{ 305b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin UINT32 CmdArg; 306b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin UINT32 Response[4]; 307e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang UINT32 Buffer[128]; 308b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin UINTN BlockSize; 309b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin UINTN CardSize; 310b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin UINTN NumBlocks; 311e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang BOOLEAN CccSwitch; 312e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang SCR Scr; 313b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin EFI_STATUS Status; 314b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin EFI_MMC_HOST_PROTOCOL *MmcHost; 315b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 316b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHost = MmcHostInstance->MmcHost; 317b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 318b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Send a command to get Card specific data 319b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin CmdArg = MmcHostInstance->CardInfo.RCA << 16; 320b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->SendCommand (MmcHost, MMC_CMD9, CmdArg); 321b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 322b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(MMC_CMD9): Error, Status=%r\n", Status)); 323b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 324b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 325b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 326b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Read Response 327b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CSD, Response); 328b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 329b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(): Failed to receive CSD, Status=%r\n", Status)); 330b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 331b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 332b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin PrintCSD (Response); 333e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (MMC_CSD_GET_CCC(Response) & SD_CCC_SWITCH) { 334e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang CccSwitch = TRUE; 335e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } else { 336e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang CccSwitch = FALSE; 337e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 338b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 339b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) { 340b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin CardSize = HC_MMC_CSD_GET_DEVICESIZE (Response); 341b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin NumBlocks = ((CardSize + 1) * 1024); 342b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response); 343b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } else { 344b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin CardSize = MMC_CSD_GET_DEVICESIZE (Response); 345b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin NumBlocks = (CardSize + 1) * (1 << (MMC_CSD_GET_DEVICESIZEMULT (Response) + 2)); 346b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response); 347b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 348b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 349b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes. 350b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (BlockSize > 512) { 351b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin NumBlocks = MultU64x32 (NumBlocks, BlockSize / 512); 352b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin BlockSize = 512; 353b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 354b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 355b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHostInstance->BlockIo.Media->LastBlock = (NumBlocks - 1); 356b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHostInstance->BlockIo.Media->BlockSize = BlockSize; 357b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHostInstance->BlockIo.Media->ReadOnly = MmcHost->IsReadOnly (MmcHost); 358b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHostInstance->BlockIo.Media->MediaPresent = TRUE; 359b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHostInstance->BlockIo.Media->MediaId++; 360b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 361b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin CmdArg = MmcHostInstance->CardInfo.RCA << 16; 362b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->SendCommand (MmcHost, MMC_CMD7, CmdArg); 363b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 364b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(MMC_CMD7): Error and Status = %r\n", Status)); 365b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 366b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 367b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 368e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, CmdArg); 369e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (EFI_ERROR (Status)) { 370e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang DEBUG ((EFI_D_ERROR, "%a(MMC_CMD55): Error and Status = %r\n", Status)); 371e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang return Status; 372e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 373e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response); 374e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (EFI_ERROR (Status)) { 375e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang DEBUG ((EFI_D_ERROR, "%a(MMC_CMD55): Error and Status = %r\n", Status)); 376e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang return Status; 377e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 378e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if ((Response[0] & MMC_STATUS_APP_CMD) == 0) { 379e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang return EFI_SUCCESS; 380e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 381e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang 382e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang /* SCR */ 383e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang Status = MmcHost->SendCommand (MmcHost, MMC_ACMD51, 0); 384e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (EFI_ERROR (Status)) { 385e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang DEBUG ((EFI_D_ERROR, "%a(MMC_ACMD51): Error and Status = %r\n", __func__, Status)); 386e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang return Status; 387e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } else { 388e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang Status = MmcHost->ReadBlockData (MmcHost, 0, 8, Buffer); 389e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (EFI_ERROR (Status)) { 390e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang DEBUG ((EFI_D_ERROR, "%a(MMC_ACMD51): ReadBlockData Error and Status = %r\n", __func__, Status)); 391e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang return Status; 392e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 393e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang CopyMem (&Scr, Buffer, 8); 394e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (Scr.SD_SPEC == 2) { 395e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (Scr.SD_SPEC3 == 1) { 396e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (Scr.SD_SPEC4 == 1) { 397e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 4.xx\n")); 398e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } else { 399e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 3.0x\n")); 400e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 401e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } else { 402e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (Scr.SD_SPEC4 == 0) { 403e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 2.0\n")); 404e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } else { 405e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang DEBUG ((EFI_D_ERROR, "Found invalid SD Card\n")); 406e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 407e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 408e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } else { 409e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if ((Scr.SD_SPEC3 == 0) && (Scr.SD_SPEC4 == 0)) { 410e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (Scr.SD_SPEC == 1) { 411e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 1.10\n")); 412e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } else { 413e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 1.0\n")); 414e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 415e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } else { 416e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang DEBUG ((EFI_D_ERROR, "Found invalid SD Card\n")); 417e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 418e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 419e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 420e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (CccSwitch) { 421e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang /* SD Switch, Mode:1, Group:0, Value:1 */ 422e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang CmdArg = 1 << 31 | 0x00FFFFFF; 423e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang CmdArg &= ~(0xF << (0 * 4)); 424e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang CmdArg |= 1 << (0 * 4); 425e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, CmdArg); 426e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (EFI_ERROR (Status)) { 427e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang DEBUG ((EFI_D_ERROR, "%a(MMC_CMD6): Error and Status = %r\n", Status)); 428e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang return Status; 429e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } else { 430e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang Status = MmcHost->ReadBlockData (MmcHost, 0, 64, Buffer); 431e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (EFI_ERROR (Status)) { 432e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang DEBUG ((EFI_D_ERROR, "%a(MMC_CMD6): ReadBlockData Error and Status = %r\n", Status)); 433e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang return Status; 434e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 435e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 436e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 437e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (Scr.SD_BUS_WIDTHS & SD_BUS_WIDTH_4BIT) { 438e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang CmdArg = MmcHostInstance->CardInfo.RCA << 16; 439e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, CmdArg); 440e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (EFI_ERROR (Status)) { 441e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang DEBUG ((EFI_D_ERROR, "%a(MMC_CMD55): Error and Status = %r\n", Status)); 442e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang return Status; 443e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 444e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang /* Width: 4 */ 445e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, 2); 446e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (EFI_ERROR (Status)) { 447e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang DEBUG ((EFI_D_ERROR, "%a(MMC_CMD6): Error and Status = %r\n", Status)); 448e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang return Status; 449e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 450e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 451e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (MMC_HOST_HAS_SETIOS(MmcHost)) { 452e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang Status = MmcHost->SetIos (MmcHost, 26 * 1000 * 1000, 4, EMMCBACKWARD); 453e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang if (EFI_ERROR (Status)) { 454e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang DEBUG ((EFI_D_ERROR, "%a(SetIos): Error and Status = %r\n", Status)); 455e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang return Status; 456e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 457e06253ba80d93bceaefc182ca882e07b0463be8dHaojian Zhuang } 458b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return EFI_SUCCESS; 459b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin} 460b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 461b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier MartinSTATIC 462b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier MartinEFI_STATUS 463b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier MartinEFIAPI 464b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier MartinMmcIdentificationMode ( 465b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin IN MMC_HOST_INSTANCE *MmcHostInstance 466b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin ) 467b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin{ 468b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin EFI_STATUS Status; 469b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin UINT32 Response[4]; 470b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin UINTN Timeout; 471b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin UINTN CmdArg; 472b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin BOOLEAN IsHCS; 473b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin EFI_MMC_HOST_PROTOCOL *MmcHost; 474b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin OCR_RESPONSE OcrResponse; 475b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 476b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHost = MmcHostInstance->MmcHost; 477b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin CmdArg = 0; 478b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin IsHCS = FALSE; 479b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 480b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (MmcHost == NULL) { 481b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return EFI_INVALID_PARAMETER; 482b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 483b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 484b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // We can get into this function if we restart the identification mode 485b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (MmcHostInstance->State == MmcHwInitializationState) { 486b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Initialize the MMC Host HW 487b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcNotifyState (MmcHostInstance, MmcHwInitializationState); 488b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 489b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState, Status=%r.\n", Status)); 490b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 491b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 492b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 493b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 494b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->SendCommand (MmcHost, MMC_CMD0, 0); 495b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 496b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD0): Error, Status=%r.\n", Status)); 497b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 498b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 499b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcNotifyState (MmcHostInstance, MmcIdleState); 500b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 501b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdleState, Status=%r.\n", Status)); 502b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 503b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 504b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 505139b57737413a7d95bc35edf4a5463a599965edbOlivier Martin // Send CMD1 to get OCR (MMC) 506139b57737413a7d95bc35edf4a5463a599965edbOlivier Martin // This command only valid for MMC and eMMC 5073201075377f80af632465361155f7498c177bad1Haojian Zhuang Timeout = MAX_RETRY_COUNT; 5083201075377f80af632465361155f7498c177bad1Haojian Zhuang do { 5093201075377f80af632465361155f7498c177bad1Haojian Zhuang Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, EMMC_CMD1_CAPACITY_GREATER_THAN_2GB); 5103201075377f80af632465361155f7498c177bad1Haojian Zhuang if (EFI_ERROR (Status)) 5113201075377f80af632465361155f7498c177bad1Haojian Zhuang break; 512b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, (UINT32 *)&OcrResponse); 513b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 514b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status)); 515b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 516b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 5173201075377f80af632465361155f7498c177bad1Haojian Zhuang Timeout--; 5183201075377f80af632465361155f7498c177bad1Haojian Zhuang } while (!OcrResponse.Ocr.PowerUp && (Timeout > 0)); 5193201075377f80af632465361155f7498c177bad1Haojian Zhuang if (Status == EFI_SUCCESS) { 520b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (!OcrResponse.Ocr.PowerUp) { 521b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD1): Card initialisation failure, Status=%r.\n", Status)); 522b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return EFI_DEVICE_ERROR; 523b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 524b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin OcrResponse.Ocr.PowerUp = 0; 525b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB) { 526b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHostInstance->CardInfo.OCRData.AccessMode = BIT1; 527b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 528b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin else { 529b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHostInstance->CardInfo.OCRData.AccessMode = 0x0; 530b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 531139b57737413a7d95bc35edf4a5463a599965edbOlivier Martin // Check whether MMC or eMMC 532b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB || 533b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin OcrResponse.Raw == EMMC_CMD1_CAPACITY_LESS_THAN_2GB) { 534b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return EmmcIdentificationMode (MmcHostInstance, OcrResponse); 535b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 536b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 537b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 538b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Are we using SDIO ? 539b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->SendCommand (MmcHost, MMC_CMD5, 0); 540b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (Status == EFI_SUCCESS) { 541b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD5): Error - SDIO not supported, Status=%r.\n", Status)); 542b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return EFI_UNSUPPORTED; 543b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 544b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 545b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Check which kind of card we are using. Ver2.00 or later SD Memory Card (PL180 is SD v1.1) 546b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin CmdArg = (0x0UL << 12 | BIT8 | 0xCEUL << 0); 547b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->SendCommand (MmcHost, MMC_CMD8, CmdArg); 548b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (Status == EFI_SUCCESS) { 549b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "Card is SD2.0 => Supports high capacity\n")); 550b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin IsHCS = TRUE; 551b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R7, Response); 552b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 553b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive response to CMD8, Status=%r.\n", Status)); 554b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 555b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 556b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin PrintResponseR1 (Response[0]); 557b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Check if it is valid response 558b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (Response[0] != CmdArg) { 559b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "The Card is not usable\n")); 560b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return EFI_UNSUPPORTED; 561b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 562b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } else { 563b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "Not a SD2.0 Card\n")); 564b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 565b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 566b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // We need to wait for the MMC or SD card is ready => (gCardInfo.OCRData.PowerUp == 1) 567b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Timeout = MAX_RETRY_COUNT; 568b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin while (Timeout > 0) { 569b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // SD Card or MMC Card ? CMD55 indicates to the card that the next command is an application specific command 570b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, 0); 571b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (Status == EFI_SUCCESS) { 572b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_INFO, "Card should be SD\n")); 573b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (IsHCS) { 574b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHostInstance->CardInfo.CardType = SD_CARD_2; 575b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } else { 576b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHostInstance->CardInfo.CardType = SD_CARD; 577b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 578b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 579b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Note: The first time CmdArg will be zero 580b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin CmdArg = ((UINTN *) &(MmcHostInstance->CardInfo.OCRData))[0]; 581b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (IsHCS) { 582b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin CmdArg |= BIT30; 583b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 584b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->SendCommand (MmcHost, MMC_ACMD41, CmdArg); 585b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (!EFI_ERROR (Status)) { 586b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response); 587b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 588b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status)); 589b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 590b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 591b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0]; 592b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 593b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } else { 594b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_INFO, "Card should be MMC\n")); 595b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHostInstance->CardInfo.CardType = MMC_CARD; 596b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 597b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, 0x800000); 598b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (!EFI_ERROR (Status)) { 599b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response); 600b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 601b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status)); 602b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 603b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 604b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0]; 605b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 606b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 607b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 608b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (!EFI_ERROR (Status)) { 609b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (!MmcHostInstance->CardInfo.OCRData.PowerUp) { 610eff98cf9daf7353274f958bea570f0da419a09a5Olivier Martin gBS->Stall (1); 611b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Timeout--; 612b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } else { 613b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if ((MmcHostInstance->CardInfo.CardType == SD_CARD_2) && (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1)) { 614b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHostInstance->CardInfo.CardType = SD_CARD_2_HIGH; 615b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "High capacity card.\n")); 616b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 617b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin break; // The MMC/SD card is ready. Continue the Identification Mode 618b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 619b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } else { 620eff98cf9daf7353274f958bea570f0da419a09a5Olivier Martin gBS->Stall (1); 621b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Timeout--; 622b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 623b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 624b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 625b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (Timeout == 0) { 626b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(): No Card\n")); 627b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return EFI_NO_MEDIA; 628b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } else { 629b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin PrintOCR (Response[0]); 630b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 631b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 632b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcNotifyState (MmcHostInstance, MmcReadyState); 633b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 634b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcReadyState\n")); 635b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 636b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 637b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 638b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->SendCommand (MmcHost, MMC_CMD2, 0); 639b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 640b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD2): Error\n")); 641b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 642b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 643b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CID, Response); 644b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 645b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive CID, Status=%r.\n", Status)); 646b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 647b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 648b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 649b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin PrintCID (Response); 650b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 651b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->NotifyState (MmcHost, MmcIdentificationState); 652b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 653b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdentificationState\n")); 654b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 655b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 656b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 657b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // 658b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Note, SD specifications say that "if the command execution causes a state change, it 659b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // will be visible to the host in the response to the next command" 660b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // The status returned for this CMD3 will be 2 - identification 661b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // 662b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin CmdArg = 1; 663b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->SendCommand (MmcHost, MMC_CMD3, CmdArg); 664b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 665b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD3): Error\n")); 666b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 667b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 668b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 669b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_RCA, Response); 670b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 671b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive RCA, Status=%r.\n", Status)); 672b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 673b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 674b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin PrintRCA (Response[0]); 675b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 676b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // For MMC card, RCA is assigned by CMD3 while CMD3 dumps the RCA for SD card 677b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (MmcHostInstance->CardInfo.CardType != MMC_CARD) { 678b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHostInstance->CardInfo.RCA = Response[0] >> 16; 679b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } else { 680b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHostInstance->CardInfo.RCA = CmdArg; 681b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 682b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcNotifyState (MmcHostInstance, MmcStandByState); 683b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 684b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcStandByState\n")); 685b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 686b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 687b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 688b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return EFI_SUCCESS; 689b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin} 690b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 691b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier MartinEFI_STATUS 692b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier MartinInitializeMmcDevice ( 693b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin IN MMC_HOST_INSTANCE *MmcHostInstance 694b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin ) 695b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin{ 696b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin EFI_STATUS Status; 697b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin EFI_MMC_HOST_PROTOCOL *MmcHost; 698b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin UINTN BlockCount; 699b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 700b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin BlockCount = 1; 701b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHost = MmcHostInstance->MmcHost; 702b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 703b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcIdentificationMode (MmcHostInstance); 704b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 705b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error in Identification Mode, Status=%r\n", Status)); 706b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 707b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 708b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 709b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcNotifyState (MmcHostInstance, MmcTransferState); 710b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 711b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error MmcTransferState, Status=%r\n", Status)); 712b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 713b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 714b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 715b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) { 716b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = InitializeSdMmcDevice (MmcHostInstance); 717752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } else { 718752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang Status = InitializeEmmcDevice (MmcHostInstance); 719752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang } 720752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang if (EFI_ERROR (Status)) { 721752ae80514ccb3532a6d6d16a122642573eabdeeHaojian Zhuang return Status; 722b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 723b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 724b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Set Block Length 725b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->SendCommand (MmcHost, MMC_CMD16, MmcHostInstance->BlockIo.Media->BlockSize); 726b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 727b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD16): Error MmcHostInstance->BlockIo.Media->BlockSize: %d and Error = %r\n", 728b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin MmcHostInstance->BlockIo.Media->BlockSize, Status)); 729b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 730b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 731b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 732b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin // Block Count (not used). Could return an error for SD card 733b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (MmcHostInstance->CardInfo.CardType == MMC_CARD) { 734b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin Status = MmcHost->SendCommand (MmcHost, MMC_CMD23, BlockCount); 735b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin if (EFI_ERROR (Status)) { 736b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD23): Error, Status=%r\n", Status)); 737b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return Status; 738b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 739b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin } 740b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin 741b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin return EFI_SUCCESS; 742b4fdedc2543c6d193c70ae5339a56824a9729e68Olivier Martin} 743