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