1 /** @file
2 
3 Block I/O protocol for MMC/SD device
4 
5 Copyright (c) 2013-2015 Intel Corporation.
6 
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8 
9 **/
10 
11 #include "SDMediaDevice.h"
12 
13 /**
14   Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
15 
16   @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
17   @param  ExtendedVerification   Indicates that the driver may perform a more exhaustive.
18                                  verification operation of the device during reset.
19                                  (This parameter is ingored in this driver.)
20 
21   @retval EFI_SUCCESS                Success
22 **/
23 EFI_STATUS
24 EFIAPI
MMCSDBlockReset(IN EFI_BLOCK_IO_PROTOCOL * This,IN BOOLEAN ExtendedVerification)25 MMCSDBlockReset (
26   IN  EFI_BLOCK_IO_PROTOCOL   *This,
27   IN  BOOLEAN                 ExtendedVerification
28   )
29 {
30   CARD_DATA                  *CardData;
31   EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
32 
33   CardData  = CARD_DATA_FROM_THIS(This);
34   SDHostIo = CardData->SDHostIo;
35 
36   return SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);
37  }
38 
39 /**
40   Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
41 
42   @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
43   @param  MediaId                The media id that the write request is for.
44   @param  LBA                    The starting logical block address to read from on the device.
45                                  The caller is responsible for writing to only legitimate locations.
46   @param  BufferSize             The size of the Buffer in bytes. This must be a multiple of the
47                                  intrinsic block size of the device.
48   @param  Buffer                 A pointer to the destination buffer for the data. The caller
49                                  is responsible for either having implicit or explicit ownership
50                                  of the buffer.
51 
52   @retval EFI_SUCCESS                Success
53   @retval EFI_DEVICE_ERROR           Hardware Error
54   @retval EFI_INVALID_PARAMETER      Parameter is error
55   @retval EFI_NO_MEDIA               No media
56   @retval EFI_MEDIA_CHANGED          Media Change
57   @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
58 **/
59 EFI_STATUS
60 EFIAPI
MMCSDBlockReadBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA LBA,IN UINTN BufferSize,OUT VOID * Buffer)61 MMCSDBlockReadBlocks (
62   IN  EFI_BLOCK_IO_PROTOCOL   *This,
63   IN  UINT32                  MediaId,
64   IN  EFI_LBA                 LBA,
65   IN  UINTN                   BufferSize,
66   OUT VOID                    *Buffer
67   )
68 {
69   EFI_STATUS                  Status;
70   UINT32                      Address;
71   CARD_DATA                   *CardData;
72   EFI_SD_HOST_IO_PROTOCOL     *SDHostIo;
73   UINT32                      RemainingLength;
74   UINT32                      TransferLength;
75   UINT8                       *BufferPointer;
76   BOOLEAN                     SectorAddressing;
77   UINTN                       TotalBlock;
78 
79   DEBUG((EFI_D_INFO, "Read(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));
80   Status   = EFI_SUCCESS;
81   CardData  = CARD_DATA_FROM_THIS(This);
82   SDHostIo = CardData->SDHostIo;
83   if (MediaId != CardData->BlockIoMedia.MediaId) {
84     return EFI_MEDIA_CHANGED;
85   }
86 
87   if (ModU64x32 (BufferSize,CardData->BlockIoMedia.BlockSize) != 0) {
88     return EFI_BAD_BUFFER_SIZE;
89   }
90   if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {
91     SectorAddressing = TRUE;
92   } else {
93     SectorAddressing = FALSE;
94   }
95   if (SectorAddressing) {
96     //
97     //Block Address
98     //
99     Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);
100   } else {
101     //
102     //Byte Address
103     //
104     Address  = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
105   }
106   TotalBlock = (UINTN) DivU64x32 (BufferSize, CardData->BlockIoMedia.BlockSize);
107   if (LBA + TotalBlock > CardData->BlockIoMedia.LastBlock + 1) {
108     return EFI_INVALID_PARAMETER;
109   }
110 
111 
112   if (!Buffer) {
113     Status = EFI_INVALID_PARAMETER;
114     DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks:Invalid parameter \r\n"));
115     goto Done;
116   }
117 
118   if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
119     Status = EFI_BAD_BUFFER_SIZE;
120     DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: Bad buffer size \r\n"));
121     goto Done;
122   }
123 
124   if (BufferSize == 0) {
125     Status = EFI_SUCCESS;
126     goto Done;
127   }
128 
129 
130 
131 
132     BufferPointer   = Buffer;
133     RemainingLength = (UINT32)BufferSize;
134 
135     while (RemainingLength > 0) {
136     if ((BufferSize > CardData->BlockIoMedia.BlockSize)) {
137       if (RemainingLength > SDHostIo->HostCapability.BoundarySize) {
138         TransferLength = SDHostIo->HostCapability.BoundarySize;
139       } else {
140         TransferLength = RemainingLength;
141       }
142 
143       if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
144         if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {
145       Status = SendCommand (
146                      CardData,
147                      SET_BLOCKLEN,
148                      CardData->BlockIoMedia.BlockSize,
149                      NoData,
150                      NULL,
151                      0,
152                      ResponseR1,
153                      TIMEOUT_COMMAND,
154                      (UINT32*)&(CardData->CardStatus)
155                      );
156           if (EFI_ERROR (Status)) {
157             break;
158           }
159         }
160         Status = SendCommand (
161                    CardData,
162                    SET_BLOCK_COUNT,
163                    TransferLength / CardData->BlockIoMedia.BlockSize,
164                    NoData,
165                    NULL,
166                    0,
167                    ResponseR1,
168                    TIMEOUT_COMMAND,
169                    (UINT32*)&(CardData->CardStatus)
170                    );
171         if (EFI_ERROR (Status)) {
172           break;
173         }
174       }
175       Status = SendCommand (
176                  CardData,
177                  READ_MULTIPLE_BLOCK,
178                  Address,
179                  InData,
180                  CardData->AlignedBuffer,
181                  TransferLength,
182                  ResponseR1,
183                  TIMEOUT_DATA,
184                  (UINT32*)&(CardData->CardStatus)
185                  );
186 
187       if (EFI_ERROR (Status)) {
188         DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_MULTIPLE_BLOCK -> Fail\n"));
189         break;
190       }
191     } else {
192       if (RemainingLength > CardData->BlockIoMedia.BlockSize) {
193         TransferLength = CardData->BlockIoMedia.BlockSize;
194       } else {
195         TransferLength = RemainingLength;
196       }
197 
198       Status = SendCommand (
199                  CardData,
200                  READ_SINGLE_BLOCK,
201                  Address,
202                  InData,
203                  CardData->AlignedBuffer,
204                  (UINT32)TransferLength,
205                  ResponseR1,
206                  TIMEOUT_DATA,
207                  (UINT32*)&(CardData->CardStatus)
208                  );
209       if (EFI_ERROR (Status)) {
210         DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_SINGLE_BLOCK -> Fail\n"));
211         break;
212       }
213     }
214       CopyMem (BufferPointer, CardData->AlignedBuffer, TransferLength);
215 
216     if (SectorAddressing) {
217         //
218         //Block Address
219         //
220         Address += TransferLength / 512;
221       } else {
222         //
223         //Byte Address
224         //
225         Address += TransferLength;
226       }
227       BufferPointer   += TransferLength;
228       RemainingLength -= TransferLength;
229    }
230 
231 
232   if (EFI_ERROR (Status)) {
233     if ((CardData->CardType == SDMemoryCard) ||
234         (CardData->CardType == SDMemoryCard2)||
235         (CardData->CardType == SDMemoryCard2High)) {
236          SendCommand (
237            CardData,
238            STOP_TRANSMISSION,
239            0,
240            NoData,
241            NULL,
242            0,
243            ResponseR1b,
244            TIMEOUT_COMMAND,
245            (UINT32*)&(CardData->CardStatus)
246            );
247     } else {
248        SendCommand (
249          CardData,
250          STOP_TRANSMISSION,
251          0,
252          NoData,
253          NULL,
254          0,
255          ResponseR1,
256          TIMEOUT_COMMAND,
257          (UINT32*)&(CardData->CardStatus)
258          );
259     }
260 
261   }
262 
263 
264 Done:
265   DEBUG((EFI_D_INFO, "MMCSDBlockReadBlocks: Status = %r\n", Status));
266   return Status;
267 }
268 
269 /**
270   Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
271 
272   @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
273   @param  MediaId                The media id that the write request is for.
274   @param  LBA                    The starting logical block address to read from on the device.
275                                  The caller is responsible for writing to only legitimate locations.
276   @param  BufferSize             The size of the Buffer in bytes. This must be a multiple of the
277                                  intrinsic block size of the device.
278   @param  Buffer                 A pointer to the destination buffer for the data. The caller
279                                  is responsible for either having implicit or explicit ownership
280                                  of the buffer.
281 
282   @retval EFI_SUCCESS                Success
283   @retval EFI_DEVICE_ERROR           Hardware Error
284   @retval EFI_INVALID_PARAMETER      Parameter is error
285   @retval EFI_NO_MEDIA               No media
286   @retval EFI_MEDIA_CHANGED          Media Change
287   @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
288 **/
289 EFI_STATUS
290 EFIAPI
MMCSDBlockWriteBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA LBA,IN UINTN BufferSize,IN VOID * Buffer)291 MMCSDBlockWriteBlocks (
292   IN  EFI_BLOCK_IO_PROTOCOL   *This,
293   IN  UINT32                  MediaId,
294   IN  EFI_LBA                 LBA,
295   IN  UINTN                   BufferSize,
296   IN  VOID                    *Buffer
297   )
298 {
299   EFI_STATUS                  Status;
300   UINT32                      Address;
301   CARD_DATA                   *CardData;
302   EFI_SD_HOST_IO_PROTOCOL     *SDHostIo;
303   UINT32                      RemainingLength;
304   UINT32                      TransferLength;
305   UINT8                       *BufferPointer;
306   BOOLEAN                     SectorAddressing;
307 
308   DEBUG((EFI_D_INFO, "Write(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));
309   Status   = EFI_SUCCESS;
310   CardData  = CARD_DATA_FROM_THIS(This);
311   SDHostIo = CardData->SDHostIo;
312   if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {
313     SectorAddressing = TRUE;
314   } else {
315     SectorAddressing = FALSE;
316   }
317   if (SectorAddressing) {
318     //
319     //Block Address
320     //
321     Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);
322   } else {
323     //
324     //Byte Address
325     //
326     Address = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
327   }
328 
329   if (!Buffer) {
330     Status = EFI_INVALID_PARAMETER;
331     DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Invalid parameter \r\n"));
332     goto Done;
333   }
334 
335   if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
336     Status = EFI_BAD_BUFFER_SIZE;
337     DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Bad buffer size \r\n"));
338     goto Done;
339   }
340 
341   if (BufferSize == 0) {
342     Status = EFI_SUCCESS;
343     goto Done;
344   }
345 
346   if (This->Media->ReadOnly == TRUE) {
347     Status = EFI_WRITE_PROTECTED;
348     DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Write protected \r\n"));
349     goto Done;
350   }
351 
352 
353 
354     BufferPointer   = Buffer;
355     RemainingLength = (UINT32)BufferSize;
356 
357     while (RemainingLength > 0) {
358     if ((BufferSize > CardData->BlockIoMedia.BlockSize) ) {
359       if (RemainingLength > SDHostIo->HostCapability.BoundarySize) {
360         TransferLength = SDHostIo->HostCapability.BoundarySize;
361       } else {
362         TransferLength = RemainingLength;
363       }
364 
365       if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
366 
367         if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3)))  {
368             Status = SendCommand (
369                        CardData,
370                        SET_BLOCKLEN,
371                        CardData->BlockIoMedia.BlockSize,
372                        NoData,
373                        NULL,
374                        0,
375                        ResponseR1,
376                        TIMEOUT_COMMAND,
377                        (UINT32*)&(CardData->CardStatus)
378                        );
379             if (EFI_ERROR (Status)) {
380               break;
381             }
382         }
383         Status = SendCommand (
384                       CardData,
385                    SET_BLOCK_COUNT,
386                    TransferLength / CardData->BlockIoMedia.BlockSize,
387                       NoData,
388                       NULL,
389                       0,
390                       ResponseR1,
391                       TIMEOUT_COMMAND,
392                       (UINT32*)&(CardData->CardStatus)
393                       );
394         if (EFI_ERROR (Status)) {
395           break;
396         }
397       }
398 
399       CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
400 
401       Status = SendCommand (
402                  CardData,
403                  WRITE_MULTIPLE_BLOCK,
404                  Address,
405                  OutData,
406                  CardData->AlignedBuffer,
407                  (UINT32)TransferLength,
408                  ResponseR1,
409                  TIMEOUT_DATA,
410                  (UINT32*)&(CardData->CardStatus)
411                  );
412       if (EFI_ERROR (Status)) {
413         DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: WRITE_MULTIPLE_BLOCK -> Fail\n"));
414         break;
415       }
416     } else {
417       if (RemainingLength > CardData->BlockIoMedia.BlockSize) {
418         TransferLength = CardData->BlockIoMedia.BlockSize;
419       } else {
420         TransferLength = RemainingLength;
421       }
422 
423       CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
424 
425       Status = SendCommand (
426                  CardData,
427                  WRITE_BLOCK,
428                  Address,
429                  OutData,
430                  CardData->AlignedBuffer,
431                  (UINT32)TransferLength,
432                  ResponseR1,
433                  TIMEOUT_DATA,
434                  (UINT32*)&(CardData->CardStatus)
435                  );
436     }
437     if (SectorAddressing) {
438         //
439         //Block Address
440         //
441         Address += TransferLength / 512;
442       } else {
443         //
444         //Byte Address
445         //
446         Address += TransferLength;
447       }
448       BufferPointer   += TransferLength;
449       RemainingLength -= TransferLength;
450 
451   }
452 
453   if (EFI_ERROR (Status)) {
454     SendCommand (
455       CardData,
456       STOP_TRANSMISSION,
457       0,
458       NoData,
459       NULL,
460       0,
461       ResponseR1b,
462       TIMEOUT_COMMAND,
463       (UINT32*)&(CardData->CardStatus)
464       );
465 
466   }
467 
468 
469 Done:
470   return EFI_SUCCESS;
471 }
472 
473 /**
474   Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
475     (In this driver, this function just returns EFI_SUCCESS.)
476 
477   @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
478 
479   @retval EFI_SUCCESS
480   @retval Others
481 **/
482 EFI_STATUS
483 EFIAPI
MMCSDBlockFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL * This)484 MMCSDBlockFlushBlocks (
485   IN  EFI_BLOCK_IO_PROTOCOL   *This
486   )
487 {
488   return EFI_SUCCESS;
489 }
490 
491 
492 /**
493   MMC/SD card BlockIo init function.
494 
495   @param  CardData               Pointer to CARD_DATA.
496 
497   @retval EFI_SUCCESS
498   @retval Others
499 **/
500 EFI_STATUS
MMCSDBlockIoInit(IN CARD_DATA * CardData)501 MMCSDBlockIoInit (
502   IN  CARD_DATA    *CardData
503   )
504 {
505   //
506   //BlockIO protocol
507   //
508   CardData->BlockIo.Revision    = EFI_BLOCK_IO_PROTOCOL_REVISION;
509   CardData->BlockIo.Media       = &(CardData->BlockIoMedia);
510   CardData->BlockIo.Reset       = MMCSDBlockReset;
511   CardData->BlockIo.ReadBlocks  = MMCSDBlockReadBlocks ;
512   CardData->BlockIo.WriteBlocks = MMCSDBlockWriteBlocks;
513   CardData->BlockIo.FlushBlocks = MMCSDBlockFlushBlocks;
514 
515   CardData->BlockIoMedia.MediaId          = 0;
516   CardData->BlockIoMedia.RemovableMedia   = FALSE;
517   CardData->BlockIoMedia.MediaPresent     = TRUE;
518   CardData->BlockIoMedia.LogicalPartition = FALSE;
519 
520   if (CardData->CSDRegister.PERM_WRITE_PROTECT || CardData->CSDRegister.TMP_WRITE_PROTECT) {
521     CardData->BlockIoMedia.ReadOnly         = TRUE;
522   } else {
523     CardData->BlockIoMedia.ReadOnly         = FALSE;
524   }
525 
526 
527   CardData->BlockIoMedia.WriteCaching     = FALSE;
528   CardData->BlockIoMedia.BlockSize        = CardData->BlockLen;
529   CardData->BlockIoMedia.IoAlign          = 1;
530   CardData->BlockIoMedia.LastBlock        = (EFI_LBA)(CardData->BlockNumber - 1);
531 
532 
533   return EFI_SUCCESS;
534 
535 }
536 
537 
538 
539