1 /** @file 2 * 3 * Copyright (c) 2011-2015, ARM Limited. All rights reserved. 4 * 5 * This program and the accompanying materials 6 * are licensed and made available under the terms and conditions of the BSD License 7 * which accompanies this distribution. The full text of the license may be found at 8 * http://opensource.org/licenses/bsd-license.php 9 * 10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 * 13 **/ 14 15 #include <Library/BaseMemoryLib.h> 16 17 #include "Mmc.h" 18 19 EFI_STATUS 20 MmcNotifyState ( 21 IN MMC_HOST_INSTANCE *MmcHostInstance, 22 IN MMC_STATE State 23 ) 24 { 25 MmcHostInstance->State = State; 26 return MmcHostInstance->MmcHost->NotifyState (MmcHostInstance->MmcHost, State); 27 } 28 29 EFI_STATUS 30 EFIAPI 31 MmcGetCardStatus ( 32 IN MMC_HOST_INSTANCE *MmcHostInstance 33 ) 34 { 35 EFI_STATUS Status; 36 UINT32 Response[4]; 37 UINTN CmdArg; 38 EFI_MMC_HOST_PROTOCOL *MmcHost; 39 40 Status = EFI_SUCCESS; 41 MmcHost = MmcHostInstance->MmcHost; 42 CmdArg = 0; 43 44 if (MmcHost == NULL) { 45 return EFI_INVALID_PARAMETER; 46 } 47 if (MmcHostInstance->State != MmcHwInitializationState) { 48 //Get the Status of the card. 49 CmdArg = MmcHostInstance->CardInfo.RCA << 16; 50 Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg); 51 if (EFI_ERROR (Status)) { 52 DEBUG ((EFI_D_ERROR, "MmcGetCardStatus(MMC_CMD13): Error and Status = %r\n", Status)); 53 return Status; 54 } 55 56 //Read Response 57 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response); 58 PrintResponseR1 (Response[0]); 59 } 60 61 return Status; 62 } 63 64 EFI_STATUS 65 EFIAPI 66 MmcReset ( 67 IN EFI_BLOCK_IO_PROTOCOL *This, 68 IN BOOLEAN ExtendedVerification 69 ) 70 { 71 MMC_HOST_INSTANCE *MmcHostInstance; 72 73 MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This); 74 75 if (MmcHostInstance->MmcHost == NULL) { 76 // Nothing to do 77 return EFI_SUCCESS; 78 } 79 80 // If a card is not present then clear all media settings 81 if (!MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost)) { 82 MmcHostInstance->BlockIo.Media->MediaPresent = FALSE; 83 MmcHostInstance->BlockIo.Media->LastBlock = 0; 84 MmcHostInstance->BlockIo.Media->BlockSize = 512; // Should be zero but there is a bug in DiskIo 85 MmcHostInstance->BlockIo.Media->ReadOnly = FALSE; 86 87 // Indicate that the driver requires initialization 88 MmcHostInstance->State = MmcHwInitializationState; 89 90 return EFI_SUCCESS; 91 } 92 93 // Implement me. Either send a CMD0 (could not work for some MMC host) or just turn off/turn 94 // on power and restart Identification mode 95 return EFI_SUCCESS; 96 } 97 98 EFI_STATUS 99 MmcDetectCard ( 100 EFI_MMC_HOST_PROTOCOL *MmcHost 101 ) 102 { 103 if (!MmcHost->IsCardPresent (MmcHost)) { 104 return EFI_NO_MEDIA; 105 } else { 106 return EFI_SUCCESS; 107 } 108 } 109 110 EFI_STATUS 111 MmcStopTransmission ( 112 EFI_MMC_HOST_PROTOCOL *MmcHost 113 ) 114 { 115 EFI_STATUS Status; 116 UINT32 Response[4]; 117 // Command 12 - Stop transmission (ends read or write) 118 // Normally only needed for streaming transfers or after error. 119 Status = MmcHost->SendCommand (MmcHost, MMC_CMD12, 0); 120 if (!EFI_ERROR (Status)) { 121 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1b, Response); 122 } 123 return Status; 124 } 125 126 #define MMCI0_BLOCKLEN 512 127 #define MMCI0_TIMEOUT 10000 128 129 STATIC EFI_STATUS 130 MmcTransferBlock ( 131 IN EFI_BLOCK_IO_PROTOCOL *This, 132 IN UINTN Cmd, 133 IN UINTN Transfer, 134 IN UINT32 MediaId, 135 IN EFI_LBA Lba, 136 IN UINTN BufferSize, 137 OUT VOID *Buffer 138 ) 139 { 140 EFI_STATUS Status; 141 UINTN CmdArg; 142 INTN Timeout; 143 UINT32 Response[4]; 144 MMC_HOST_INSTANCE *MmcHostInstance; 145 EFI_MMC_HOST_PROTOCOL *MmcHost; 146 147 MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This); 148 MmcHost = MmcHostInstance->MmcHost; 149 150 //Set command argument based on the card access mode (Byte mode or Block mode) 151 if (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1) { 152 CmdArg = Lba; 153 } else { 154 CmdArg = Lba * This->Media->BlockSize; 155 } 156 157 Status = MmcHost->SendCommand (MmcHost, Cmd, CmdArg); 158 if (EFI_ERROR (Status)) { 159 DEBUG ((EFI_D_ERROR, "%a(MMC_CMD%d): Error %r\n", __func__, Cmd, Status)); 160 return Status; 161 } 162 163 if (Transfer == MMC_IOBLOCKS_READ) { 164 // Read Data 165 Status = MmcHost->ReadBlockData (MmcHost, Lba, BufferSize, Buffer); 166 if (EFI_ERROR (Status)) { 167 DEBUG ((EFI_D_BLKIO, "%a(): Error Read Block Data and Status = %r\n", __func__, Status)); 168 MmcStopTransmission (MmcHost); 169 return Status; 170 } 171 Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState); 172 if (EFI_ERROR (Status)) { 173 DEBUG ((EFI_D_ERROR, "%a() : Error MmcProgrammingState\n", __func__)); 174 return Status; 175 } 176 } else { 177 // Write Data 178 Status = MmcHost->WriteBlockData (MmcHost, Lba, BufferSize, Buffer); 179 if (EFI_ERROR (Status)) { 180 DEBUG ((EFI_D_BLKIO, "%a(): Error Write Block Data and Status = %r\n", __func__, Status)); 181 MmcStopTransmission (MmcHost); 182 return Status; 183 } 184 } 185 186 // Command 13 - Read status and wait for programming to complete (return to tran) 187 Timeout = MMCI0_TIMEOUT; 188 CmdArg = MmcHostInstance->CardInfo.RCA << 16; 189 Response[0] = 0; 190 while( (!(Response[0] & MMC_R0_READY_FOR_DATA)) 191 && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN) 192 && Timeout--) { 193 Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg); 194 if (!EFI_ERROR (Status)) { 195 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response); 196 if ((Response[0] & MMC_R0_READY_FOR_DATA)) { 197 break; // Prevents delay once finished 198 } 199 } 200 gBS->Stall (1); 201 } 202 203 if (BufferSize > This->Media->BlockSize) { 204 Status = MmcHost->SendCommand (MmcHost, MMC_CMD12, 0); 205 if (EFI_ERROR (Status)) { 206 DEBUG ((EFI_D_BLKIO, "%a(): Error and Status:%r\n", __func__, Status)); 207 } 208 } 209 210 Status = MmcNotifyState (MmcHostInstance, MmcTransferState); 211 if (EFI_ERROR (Status)) { 212 DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcTransferState\n")); 213 return Status; 214 } 215 return Status; 216 } 217 218 EFI_STATUS 219 MmcIoBlocks ( 220 IN EFI_BLOCK_IO_PROTOCOL *This, 221 IN UINTN Transfer, 222 IN UINT32 MediaId, 223 IN EFI_LBA Lba, 224 IN UINTN BufferSize, 225 OUT VOID *Buffer 226 ) 227 { 228 UINT32 Response[4]; 229 EFI_STATUS Status; 230 UINTN CmdArg; 231 INTN Timeout; 232 UINTN Cmd; 233 MMC_HOST_INSTANCE *MmcHostInstance; 234 EFI_MMC_HOST_PROTOCOL *MmcHost; 235 UINTN BytesRemainingToBeTransfered; 236 UINTN BlockCount; 237 UINTN ConsumeSize; 238 239 BlockCount = 1; 240 MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This); 241 ASSERT (MmcHostInstance != NULL); 242 MmcHost = MmcHostInstance->MmcHost; 243 ASSERT (MmcHost); 244 245 if (This->Media->MediaId != MediaId) { 246 return EFI_MEDIA_CHANGED; 247 } 248 249 if ((MmcHost == NULL) || (Buffer == NULL)) { 250 return EFI_INVALID_PARAMETER; 251 } 252 253 // Check if a Card is Present 254 if (!MmcHostInstance->BlockIo.Media->MediaPresent) { 255 return EFI_NO_MEDIA; 256 } 257 258 if (MmcHost->IsMultiBlock && MmcHost->IsMultiBlock(MmcHost)) { 259 BlockCount = (BufferSize + This->Media->BlockSize - 1) / This->Media->BlockSize; 260 } 261 262 // All blocks must be within the device 263 if ((Lba + (BufferSize / This->Media->BlockSize)) > (This->Media->LastBlock + 1)) { 264 return EFI_INVALID_PARAMETER; 265 } 266 267 if ((Transfer == MMC_IOBLOCKS_WRITE) && (This->Media->ReadOnly == TRUE)) { 268 return EFI_WRITE_PROTECTED; 269 } 270 271 // Reading 0 Byte is valid 272 if (BufferSize == 0) { 273 return EFI_SUCCESS; 274 } 275 276 // The buffer size must be an exact multiple of the block size 277 if ((BufferSize % This->Media->BlockSize) != 0) { 278 return EFI_BAD_BUFFER_SIZE; 279 } 280 281 // Check the alignment 282 if ((This->Media->IoAlign > 2) && (((UINTN)Buffer & (This->Media->IoAlign - 1)) != 0)) { 283 return EFI_INVALID_PARAMETER; 284 } 285 286 BytesRemainingToBeTransfered = BufferSize; 287 while (BytesRemainingToBeTransfered > 0) { 288 289 // Check if the Card is in Ready status 290 CmdArg = MmcHostInstance->CardInfo.RCA << 16; 291 Response[0] = 0; 292 Timeout = 20; 293 while( (!(Response[0] & MMC_R0_READY_FOR_DATA)) 294 && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN) 295 && Timeout--) { 296 Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg); 297 if (!EFI_ERROR (Status)) { 298 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response); 299 } 300 } 301 302 if (0 == Timeout) { 303 DEBUG ((EFI_D_ERROR, "The Card is busy\n")); 304 return EFI_NOT_READY; 305 } 306 307 if (Transfer == MMC_IOBLOCKS_READ) { 308 if (BlockCount == 1) { 309 // Read a single block 310 Cmd = MMC_CMD17; 311 } else { 312 // Read multiple blocks 313 Cmd = MMC_CMD18; 314 } 315 } else { 316 if (BlockCount == 1) { 317 // Write a single block 318 Cmd = MMC_CMD24; 319 } else { 320 // Write multiple blocks 321 Cmd = MMC_CMD25; 322 } 323 } 324 325 ConsumeSize = BlockCount * This->Media->BlockSize; 326 if (BytesRemainingToBeTransfered < ConsumeSize) { 327 ConsumeSize = BytesRemainingToBeTransfered; 328 } 329 Status = MmcTransferBlock (This, Cmd, Transfer, MediaId, Lba, ConsumeSize, Buffer); 330 if (EFI_ERROR (Status)) { 331 DEBUG ((EFI_D_ERROR, "%a(): Failed to transfer block and Status:%r\n", __func__, Status)); 332 } 333 334 BytesRemainingToBeTransfered -= ConsumeSize; 335 if (BytesRemainingToBeTransfered > 0) { 336 Lba += BlockCount; 337 Buffer = (UINT8 *)Buffer + ConsumeSize; 338 } 339 } 340 341 return EFI_SUCCESS; 342 } 343 344 EFI_STATUS 345 EFIAPI 346 MmcReadBlocks ( 347 IN EFI_BLOCK_IO_PROTOCOL *This, 348 IN UINT32 MediaId, 349 IN EFI_LBA Lba, 350 IN UINTN BufferSize, 351 OUT VOID *Buffer 352 ) 353 { 354 return MmcIoBlocks (This, MMC_IOBLOCKS_READ, MediaId, Lba, BufferSize, Buffer); 355 } 356 357 EFI_STATUS 358 EFIAPI 359 MmcWriteBlocks ( 360 IN EFI_BLOCK_IO_PROTOCOL *This, 361 IN UINT32 MediaId, 362 IN EFI_LBA Lba, 363 IN UINTN BufferSize, 364 IN VOID *Buffer 365 ) 366 { 367 return MmcIoBlocks (This, MMC_IOBLOCKS_WRITE, MediaId, Lba, BufferSize, Buffer); 368 } 369 370 EFI_STATUS 371 EFIAPI 372 MmcFlushBlocks ( 373 IN EFI_BLOCK_IO_PROTOCOL *This 374 ) 375 { 376 return EFI_SUCCESS; 377 } 378 379 EFI_STATUS 380 EFIAPI 381 MmcEraseBlocks ( 382 IN EFI_BLOCK_IO_PROTOCOL *This, 383 IN UINT32 MediaId, 384 IN EFI_LBA Lba, 385 IN OUT EFI_ERASE_BLOCK_TOKEN *Token, 386 IN UINTN Size 387 ) 388 { 389 EFI_STATUS Status; 390 MMC_HOST_INSTANCE *MmcHostInstance; 391 EFI_MMC_HOST_PROTOCOL *MmcHost; 392 UINT32 Response[4]; 393 UINTN CmdArg; 394 395 MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This); 396 ASSERT (MmcHostInstance != NULL); 397 MmcHost = MmcHostInstance->MmcHost; 398 ASSERT (MmcHost); 399 400 if (This->Media->ReadOnly == TRUE) 401 return EFI_WRITE_PROTECTED; 402 403 // EFI_DEVICE_ERROR, EFI_INVALID_PARAMETER 404 405 if (!MmcHostInstance->BlockIo.Media->MediaPresent) 406 return EFI_NO_MEDIA; 407 408 if (This->Media->MediaId != MediaId) 409 return EFI_MEDIA_CHANGED; 410 411 CmdArg = Lba; 412 Status = MmcHost->SendCommand (MmcHost, MMC_CMD35, CmdArg); 413 if (!EFI_ERROR (Status)) { 414 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response); 415 } 416 417 CmdArg = Lba + Size; 418 Status = MmcHost->SendCommand (MmcHost, MMC_CMD36, CmdArg); 419 if (!EFI_ERROR (Status)) { 420 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response); 421 } 422 423 CmdArg = 0; 424 Status = MmcHost->SendCommand (MmcHost, MMC_CMD38, CmdArg); 425 if (!EFI_ERROR (Status)) { 426 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1b, Response); 427 } 428 429 return EFI_SUCCESS; 430 } 431