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