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