]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c
EmbeddedPkg/MmcDxe: set I/O speed and bus width in SD stack
[mirror_edk2.git] / EmbeddedPkg / Universal / MmcDxe / MmcBlockIo.c
... / ...
CommitLineData
1/** @file\r
2*\r
3* Copyright (c) 2011-2015, ARM Limited. All rights reserved.\r
4*\r
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
12*\r
13**/\r
14\r
15#include <Library/BaseMemoryLib.h>\r
16\r
17#include "Mmc.h"\r
18\r
19EFI_STATUS\r
20MmcNotifyState (\r
21 IN MMC_HOST_INSTANCE *MmcHostInstance,\r
22 IN MMC_STATE State\r
23 )\r
24{\r
25 MmcHostInstance->State = State;\r
26 return MmcHostInstance->MmcHost->NotifyState (MmcHostInstance->MmcHost, State);\r
27}\r
28\r
29EFI_STATUS\r
30EFIAPI\r
31MmcGetCardStatus (\r
32 IN MMC_HOST_INSTANCE *MmcHostInstance\r
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
47 if (MmcHostInstance->State != MmcHwInitializationState) {\r
48 //Get the Status of the card.\r
49 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
50 Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
51 if (EFI_ERROR (Status)) {\r
52 DEBUG ((EFI_D_ERROR, "MmcGetCardStatus(MMC_CMD13): Error and Status = %r\n", Status));\r
53 return Status;\r
54 }\r
55\r
56 //Read Response\r
57 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
58 PrintResponseR1 (Response[0]);\r
59 }\r
60\r
61 return Status;\r
62}\r
63\r
64EFI_STATUS\r
65EFIAPI\r
66MmcReset (\r
67 IN EFI_BLOCK_IO_PROTOCOL *This,\r
68 IN BOOLEAN ExtendedVerification\r
69 )\r
70{\r
71 MMC_HOST_INSTANCE *MmcHostInstance;\r
72\r
73 MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);\r
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
81 if (!MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost)) {\r
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
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
96}\r
97\r
98EFI_STATUS\r
99MmcDetectCard (\r
100 EFI_MMC_HOST_PROTOCOL *MmcHost\r
101 )\r
102{\r
103 if (!MmcHost->IsCardPresent (MmcHost)) {\r
104 return EFI_NO_MEDIA;\r
105 } else {\r
106 return EFI_SUCCESS;\r
107 }\r
108}\r
109\r
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
126#define MMCI0_BLOCKLEN 512\r
127#define MMCI0_TIMEOUT 10000\r
128\r
129EFI_STATUS\r
130MmcIoBlocks (\r
131 IN EFI_BLOCK_IO_PROTOCOL *This,\r
132 IN UINTN Transfer,\r
133 IN UINT32 MediaId,\r
134 IN EFI_LBA Lba,\r
135 IN UINTN BufferSize,\r
136 OUT VOID *Buffer\r
137 )\r
138{\r
139 UINT32 Response[4];\r
140 EFI_STATUS Status;\r
141 UINTN CmdArg;\r
142 INTN Timeout;\r
143 UINTN Cmd;\r
144 MMC_HOST_INSTANCE *MmcHostInstance;\r
145 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
146 UINTN BytesRemainingToBeTransfered;\r
147 UINTN BlockCount;\r
148\r
149 BlockCount = 1;\r
150 MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);\r
151 ASSERT (MmcHostInstance != NULL);\r
152 MmcHost = MmcHostInstance->MmcHost;\r
153 ASSERT (MmcHost);\r
154\r
155 if (This->Media->MediaId != MediaId) {\r
156 return EFI_MEDIA_CHANGED;\r
157 }\r
158\r
159 if ((MmcHost == NULL) || (Buffer == NULL)) {\r
160 return EFI_INVALID_PARAMETER;\r
161 }\r
162\r
163 // Check if a Card is Present\r
164 if (!MmcHostInstance->BlockIo.Media->MediaPresent) {\r
165 return EFI_NO_MEDIA;\r
166 }\r
167\r
168 // All blocks must be within the device\r
169 if ((Lba + (BufferSize / This->Media->BlockSize)) > (This->Media->LastBlock + 1)) {\r
170 return EFI_INVALID_PARAMETER;\r
171 }\r
172\r
173 if ((Transfer == MMC_IOBLOCKS_WRITE) && (This->Media->ReadOnly == TRUE)) {\r
174 return EFI_WRITE_PROTECTED;\r
175 }\r
176\r
177 // Reading 0 Byte is valid\r
178 if (BufferSize == 0) {\r
179 return EFI_SUCCESS;\r
180 }\r
181\r
182 // The buffer size must be an exact multiple of the block size\r
183 if ((BufferSize % This->Media->BlockSize) != 0) {\r
184 return EFI_BAD_BUFFER_SIZE;\r
185 }\r
186\r
187 // Check the alignment\r
188 if ((This->Media->IoAlign > 2) && (((UINTN)Buffer & (This->Media->IoAlign - 1)) != 0)) {\r
189 return EFI_INVALID_PARAMETER;\r
190 }\r
191\r
192 BytesRemainingToBeTransfered = BufferSize;\r
193 while (BytesRemainingToBeTransfered > 0) {\r
194\r
195 // Check if the Card is in Ready status\r
196 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
197 Response[0] = 0;\r
198 Timeout = 20;\r
199 while( (!(Response[0] & MMC_R0_READY_FOR_DATA))\r
200 && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN)\r
201 && Timeout--) {\r
202 Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
203 if (!EFI_ERROR (Status)) {\r
204 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
205 }\r
206 }\r
207\r
208 if (0 == Timeout) {\r
209 DEBUG ((EFI_D_ERROR, "The Card is busy\n"));\r
210 return EFI_NOT_READY;\r
211 }\r
212\r
213 //Set command argument based on the card access mode (Byte mode or Block mode)\r
214 if (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1) {\r
215 CmdArg = Lba;\r
216 } else {\r
217 CmdArg = Lba * This->Media->BlockSize;\r
218 }\r
219\r
220 if (Transfer == MMC_IOBLOCKS_READ) {\r
221 // Read a single block\r
222 Cmd = MMC_CMD17;\r
223 } else {\r
224 // Write a single block\r
225 Cmd = MMC_CMD24;\r
226 }\r
227 Status = MmcHost->SendCommand (MmcHost, Cmd, CmdArg);\r
228 if (EFI_ERROR (Status)) {\r
229 DEBUG ((EFI_D_ERROR, "MmcIoBlocks(MMC_CMD%d): Error %r\n", Cmd, Status));\r
230 return Status;\r
231 }\r
232\r
233 if (Transfer == MMC_IOBLOCKS_READ) {\r
234 // Read one block of Data\r
235 Status = MmcHost->ReadBlockData (MmcHost, Lba, This->Media->BlockSize, Buffer);\r
236 if (EFI_ERROR (Status)) {\r
237 DEBUG ((EFI_D_BLKIO, "MmcIoBlocks(): Error Read Block Data and Status = %r\n", Status));\r
238 MmcStopTransmission (MmcHost);\r
239 return Status;\r
240 }\r
241 Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState);\r
242 if (EFI_ERROR (Status)) {\r
243 DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcProgrammingState\n"));\r
244 return Status;\r
245 }\r
246 } else {\r
247 // Write one block of Data\r
248 Status = MmcHost->WriteBlockData (MmcHost, Lba, This->Media->BlockSize, Buffer);\r
249 if (EFI_ERROR (Status)) {\r
250 DEBUG ((EFI_D_BLKIO, "MmcIoBlocks(): Error Write Block Data and Status = %r\n", Status));\r
251 MmcStopTransmission (MmcHost);\r
252 return Status;\r
253 }\r
254 }\r
255\r
256 // Command 13 - Read status and wait for programming to complete (return to tran)\r
257 Timeout = MMCI0_TIMEOUT;\r
258 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
259 Response[0] = 0;\r
260 while( (!(Response[0] & MMC_R0_READY_FOR_DATA))\r
261 && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN)\r
262 && Timeout--) {\r
263 Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
264 if (!EFI_ERROR (Status)) {\r
265 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
266 if ((Response[0] & MMC_R0_READY_FOR_DATA)) {\r
267 break; // Prevents delay once finished\r
268 }\r
269 }\r
270 gBS->Stall (1);\r
271 }\r
272\r
273 Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
274 if (EFI_ERROR (Status)) {\r
275 DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcTransferState\n"));\r
276 return Status;\r
277 }\r
278\r
279 BytesRemainingToBeTransfered -= This->Media->BlockSize;\r
280 Lba += BlockCount;\r
281 Buffer = (UINT8 *)Buffer + This->Media->BlockSize;\r
282 }\r
283\r
284 return EFI_SUCCESS;\r
285}\r
286\r
287EFI_STATUS\r
288EFIAPI\r
289MmcReadBlocks (\r
290 IN EFI_BLOCK_IO_PROTOCOL *This,\r
291 IN UINT32 MediaId,\r
292 IN EFI_LBA Lba,\r
293 IN UINTN BufferSize,\r
294 OUT VOID *Buffer\r
295 )\r
296{\r
297 return MmcIoBlocks (This, MMC_IOBLOCKS_READ, MediaId, Lba, BufferSize, Buffer);\r
298}\r
299\r
300EFI_STATUS\r
301EFIAPI\r
302MmcWriteBlocks (\r
303 IN EFI_BLOCK_IO_PROTOCOL *This,\r
304 IN UINT32 MediaId,\r
305 IN EFI_LBA Lba,\r
306 IN UINTN BufferSize,\r
307 IN VOID *Buffer\r
308 )\r
309{\r
310 return MmcIoBlocks (This, MMC_IOBLOCKS_WRITE, MediaId, Lba, BufferSize, Buffer);\r
311}\r
312\r
313EFI_STATUS\r
314EFIAPI\r
315MmcFlushBlocks (\r
316 IN EFI_BLOCK_IO_PROTOCOL *This\r
317 )\r
318{\r
319 return EFI_SUCCESS;\r
320}\r