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