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