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