MmcBlockIo.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  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. #include <Library/BaseMemoryLib.h>
  15. #include "Mmc.h"
  16. EFI_STATUS
  17. MmcNotifyState (
  18. IN MMC_HOST_INSTANCE *MmcHostInstance,
  19. IN MMC_STATE State
  20. )
  21. {
  22. MmcHostInstance->State = State;
  23. return MmcHostInstance->MmcHost->NotifyState (MmcHostInstance->MmcHost, State);
  24. }
  25. EFI_STATUS
  26. EFIAPI
  27. MmcGetCardStatus (
  28. IN MMC_HOST_INSTANCE *MmcHostInstance
  29. )
  30. {
  31. EFI_STATUS Status;
  32. UINT32 Response[4];
  33. UINTN CmdArg;
  34. EFI_MMC_HOST_PROTOCOL *MmcHost;
  35. Status = EFI_SUCCESS;
  36. MmcHost = MmcHostInstance->MmcHost;
  37. CmdArg = 0;
  38. if (MmcHost == NULL) {
  39. return EFI_INVALID_PARAMETER;
  40. }
  41. if (MmcHostInstance->State != MmcHwInitializationState) {
  42. //Get the Status of the card.
  43. CmdArg = MmcHostInstance->CardInfo.RCA << 16;
  44. Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);
  45. if (EFI_ERROR (Status)) {
  46. DEBUG ((EFI_D_ERROR, "MmcGetCardStatus(MMC_CMD13): Error and Status = %r\n", Status));
  47. return Status;
  48. }
  49. //Read Response
  50. MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);
  51. PrintResponseR1 (Response[0]);
  52. }
  53. return Status;
  54. }
  55. EFI_STATUS
  56. EFIAPI
  57. MmcReset (
  58. IN EFI_BLOCK_IO_PROTOCOL *This,
  59. IN BOOLEAN ExtendedVerification
  60. )
  61. {
  62. MMC_HOST_INSTANCE *MmcHostInstance;
  63. MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);
  64. if (MmcHostInstance->MmcHost == NULL) {
  65. // Nothing to do
  66. return EFI_SUCCESS;
  67. }
  68. // If a card is not present then clear all media settings
  69. if (!MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost)) {
  70. MmcHostInstance->BlockIo.Media->MediaPresent = FALSE;
  71. MmcHostInstance->BlockIo.Media->LastBlock = 0;
  72. MmcHostInstance->BlockIo.Media->BlockSize = 512; // Should be zero but there is a bug in DiskIo
  73. MmcHostInstance->BlockIo.Media->ReadOnly = FALSE;
  74. // Indicate that the driver requires initialization
  75. MmcHostInstance->State = MmcHwInitializationState;
  76. return EFI_SUCCESS;
  77. }
  78. // Implement me. Either send a CMD0 (could not work for some MMC host) or just turn off/turn
  79. // on power and restart Identification mode
  80. return EFI_SUCCESS;
  81. }
  82. EFI_STATUS
  83. MmcDetectCard (
  84. EFI_MMC_HOST_PROTOCOL *MmcHost
  85. )
  86. {
  87. if (!MmcHost->IsCardPresent (MmcHost)) {
  88. return EFI_NO_MEDIA;
  89. } else {
  90. return EFI_SUCCESS;
  91. }
  92. }
  93. EFI_STATUS
  94. MmcStopTransmission (
  95. EFI_MMC_HOST_PROTOCOL *MmcHost
  96. )
  97. {
  98. EFI_STATUS Status;
  99. UINT32 Response[4];
  100. // Command 12 - Stop transmission (ends read or write)
  101. // Normally only needed for streaming transfers or after error.
  102. Status = MmcHost->SendCommand (MmcHost, MMC_CMD12, 0);
  103. if (!EFI_ERROR (Status)) {
  104. MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1b, Response);
  105. }
  106. return Status;
  107. }
  108. #define MMCI0_BLOCKLEN 512
  109. #define MMCI0_TIMEOUT 10000
  110. STATIC
  111. EFI_STATUS
  112. MmcTransferBlock (
  113. IN EFI_BLOCK_IO_PROTOCOL *This,
  114. IN UINTN Cmd,
  115. IN UINTN Transfer,
  116. IN UINT32 MediaId,
  117. IN EFI_LBA Lba,
  118. IN UINTN BufferSize,
  119. OUT VOID *Buffer
  120. )
  121. {
  122. EFI_STATUS Status;
  123. UINTN CmdArg;
  124. INTN Timeout;
  125. UINT32 Response[4];
  126. MMC_HOST_INSTANCE *MmcHostInstance;
  127. EFI_MMC_HOST_PROTOCOL *MmcHost;
  128. MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);
  129. MmcHost = MmcHostInstance->MmcHost;
  130. if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) {
  131. //Set command argument based on the card capacity
  132. //if 0 : SDSC card
  133. //if 1 : SDXC/SDHC
  134. if (MmcHostInstance->CardInfo.OCRData.AccessMode & SD_CARD_CAPACITY) {
  135. CmdArg = Lba;
  136. } else {
  137. CmdArg = Lba * This->Media->BlockSize;
  138. }
  139. } else {
  140. //Set command argument based on the card access mode (Byte mode or Block mode)
  141. if ((MmcHostInstance->CardInfo.OCRData.AccessMode & MMC_OCR_ACCESS_MASK) ==
  142. MMC_OCR_ACCESS_SECTOR) {
  143. CmdArg = Lba;
  144. } else {
  145. CmdArg = Lba * This->Media->BlockSize;
  146. }
  147. }
  148. Status = MmcHost->SendCommand (MmcHost, Cmd, CmdArg);
  149. if (EFI_ERROR (Status)) {
  150. DEBUG ((EFI_D_ERROR, "%a(MMC_CMD%d): Error %r\n", __func__, Cmd, Status));
  151. return Status;
  152. }
  153. if (Transfer == MMC_IOBLOCKS_READ) {
  154. // Read Data
  155. Status = MmcHost->ReadBlockData (MmcHost, Lba, BufferSize, Buffer);
  156. if (EFI_ERROR (Status)) {
  157. DEBUG ((EFI_D_BLKIO, "%a(): Error Read Block Data and Status = %r\n", __func__, Status));
  158. MmcStopTransmission (MmcHost);
  159. return Status;
  160. }
  161. Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState);
  162. if (EFI_ERROR (Status)) {
  163. DEBUG ((EFI_D_ERROR, "%a() : Error MmcProgrammingState\n", __func__));
  164. return Status;
  165. }
  166. } else {
  167. // Write Data
  168. Status = MmcHost->WriteBlockData (MmcHost, Lba, BufferSize, Buffer);
  169. if (EFI_ERROR (Status)) {
  170. DEBUG ((EFI_D_BLKIO, "%a(): Error Write Block Data and Status = %r\n", __func__, Status));
  171. MmcStopTransmission (MmcHost);
  172. return Status;
  173. }
  174. }
  175. // Command 13 - Read status and wait for programming to complete (return to tran)
  176. Timeout = MMCI0_TIMEOUT;
  177. CmdArg = MmcHostInstance->CardInfo.RCA << 16;
  178. Response[0] = 0;
  179. while(!(Response[0] & MMC_R0_READY_FOR_DATA)
  180. && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN)
  181. && Timeout--) {
  182. Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);
  183. if (!EFI_ERROR (Status)) {
  184. MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);
  185. if (Response[0] & MMC_R0_READY_FOR_DATA) {
  186. break; // Prevents delay once finished
  187. }
  188. }
  189. }
  190. if (BufferSize > This->Media->BlockSize) {
  191. Status = MmcHost->SendCommand (MmcHost, MMC_CMD12, 0);
  192. if (EFI_ERROR (Status)) {
  193. DEBUG ((EFI_D_BLKIO, "%a(): Error and Status:%r\n", __func__, Status));
  194. }
  195. MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1b, Response);
  196. }
  197. Status = MmcNotifyState (MmcHostInstance, MmcTransferState);
  198. if (EFI_ERROR (Status)) {
  199. DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcTransferState\n"));
  200. return Status;
  201. }
  202. return Status;
  203. }
  204. EFI_STATUS
  205. MmcIoBlocks (
  206. IN EFI_BLOCK_IO_PROTOCOL *This,
  207. IN UINTN Transfer,
  208. IN UINT32 MediaId,
  209. IN EFI_LBA Lba,
  210. IN UINTN BufferSize,
  211. OUT VOID *Buffer
  212. )
  213. {
  214. UINT32 Response[4];
  215. EFI_STATUS Status;
  216. UINTN CmdArg;
  217. INTN Timeout;
  218. UINTN Cmd;
  219. MMC_HOST_INSTANCE *MmcHostInstance;
  220. EFI_MMC_HOST_PROTOCOL *MmcHost;
  221. UINTN BytesRemainingToBeTransfered;
  222. UINTN BlockCount;
  223. UINTN ConsumeSize;
  224. BlockCount = 1;
  225. MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);
  226. ASSERT (MmcHostInstance != NULL);
  227. MmcHost = MmcHostInstance->MmcHost;
  228. ASSERT (MmcHost);
  229. if (This->Media->MediaId != MediaId) {
  230. return EFI_MEDIA_CHANGED;
  231. }
  232. if ((MmcHost == NULL) || (Buffer == NULL)) {
  233. return EFI_INVALID_PARAMETER;
  234. }
  235. // Check if a Card is Present
  236. if (!MmcHostInstance->BlockIo.Media->MediaPresent) {
  237. return EFI_NO_MEDIA;
  238. }
  239. if (MMC_HOST_HAS_ISMULTIBLOCK(MmcHost) && MmcHost->IsMultiBlock(MmcHost)) {
  240. BlockCount = (BufferSize + This->Media->BlockSize - 1) / This->Media->BlockSize;
  241. }
  242. // All blocks must be within the device
  243. if ((Lba + (BufferSize / This->Media->BlockSize)) > (This->Media->LastBlock + 1)) {
  244. return EFI_INVALID_PARAMETER;
  245. }
  246. if ((Transfer == MMC_IOBLOCKS_WRITE) && (This->Media->ReadOnly == TRUE)) {
  247. return EFI_WRITE_PROTECTED;
  248. }
  249. // Reading 0 Byte is valid
  250. if (BufferSize == 0) {
  251. return EFI_SUCCESS;
  252. }
  253. // The buffer size must be an exact multiple of the block size
  254. if ((BufferSize % This->Media->BlockSize) != 0) {
  255. return EFI_BAD_BUFFER_SIZE;
  256. }
  257. // Check the alignment
  258. if ((This->Media->IoAlign > 2) && (((UINTN)Buffer & (This->Media->IoAlign - 1)) != 0)) {
  259. return EFI_INVALID_PARAMETER;
  260. }
  261. BytesRemainingToBeTransfered = BufferSize;
  262. while (BytesRemainingToBeTransfered > 0) {
  263. // Check if the Card is in Ready status
  264. CmdArg = MmcHostInstance->CardInfo.RCA << 16;
  265. Response[0] = 0;
  266. Timeout = 20;
  267. while( (!(Response[0] & MMC_R0_READY_FOR_DATA))
  268. && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN)
  269. && Timeout--) {
  270. Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);
  271. if (!EFI_ERROR (Status)) {
  272. MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);
  273. }
  274. }
  275. if (0 == Timeout) {
  276. DEBUG ((EFI_D_ERROR, "The Card is busy\n"));
  277. return EFI_NOT_READY;
  278. }
  279. if (Transfer == MMC_IOBLOCKS_READ) {
  280. if (BlockCount == 1) {
  281. // Read a single block
  282. Cmd = MMC_CMD17;
  283. } else {
  284. // Read multiple blocks
  285. Cmd = MMC_CMD18;
  286. }
  287. } else {
  288. if (BlockCount == 1) {
  289. // Write a single block
  290. Cmd = MMC_CMD24;
  291. } else {
  292. // Write multiple blocks
  293. Cmd = MMC_CMD25;
  294. }
  295. }
  296. ConsumeSize = BlockCount * This->Media->BlockSize;
  297. if (BytesRemainingToBeTransfered < ConsumeSize) {
  298. ConsumeSize = BytesRemainingToBeTransfered;
  299. }
  300. Status = MmcTransferBlock (This, Cmd, Transfer, MediaId, Lba, ConsumeSize, Buffer);
  301. if (EFI_ERROR (Status)) {
  302. DEBUG ((EFI_D_ERROR, "%a(): Failed to transfer block and Status:%r\n", __func__, Status));
  303. }
  304. BytesRemainingToBeTransfered -= ConsumeSize;
  305. if (BytesRemainingToBeTransfered > 0) {
  306. Lba += BlockCount;
  307. Buffer = (UINT8 *)Buffer + ConsumeSize;
  308. }
  309. }
  310. return EFI_SUCCESS;
  311. }
  312. EFI_STATUS
  313. EFIAPI
  314. MmcReadBlocks (
  315. IN EFI_BLOCK_IO_PROTOCOL *This,
  316. IN UINT32 MediaId,
  317. IN EFI_LBA Lba,
  318. IN UINTN BufferSize,
  319. OUT VOID *Buffer
  320. )
  321. {
  322. return MmcIoBlocks (This, MMC_IOBLOCKS_READ, MediaId, Lba, BufferSize, Buffer);
  323. }
  324. EFI_STATUS
  325. EFIAPI
  326. MmcWriteBlocks (
  327. IN EFI_BLOCK_IO_PROTOCOL *This,
  328. IN UINT32 MediaId,
  329. IN EFI_LBA Lba,
  330. IN UINTN BufferSize,
  331. IN VOID *Buffer
  332. )
  333. {
  334. return MmcIoBlocks (This, MMC_IOBLOCKS_WRITE, MediaId, Lba, BufferSize, Buffer);
  335. }
  336. EFI_STATUS
  337. EFIAPI
  338. MmcFlushBlocks (
  339. IN EFI_BLOCK_IO_PROTOCOL *This
  340. )
  341. {
  342. return EFI_SUCCESS;
  343. }