• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 
3   Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
4   This program and the accompanying materials
5   are licensed and made available under the terms and conditions of the BSD License
6   which accompanies this distribution.  The full text of the license may be found at
7   http://opensource.org/licenses/bsd-license.php
8 
9   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 **/
13 
14 #include "EmmcBlockIoPei.h"
15 
16 //
17 // Template for EMMC HC Slot Data.
18 //
19 EMMC_PEIM_HC_SLOT   gEmmcHcSlotTemplate = {
20   EMMC_PEIM_SLOT_SIG,             // Signature
21   {                               // Media
22     {
23       MSG_EMMC_DP,
24       FALSE,
25       TRUE,
26       FALSE,
27       0x200,
28       0
29     },
30     {
31       MSG_EMMC_DP,
32       FALSE,
33       TRUE,
34       FALSE,
35       0x200,
36       0
37     },
38     {
39       MSG_EMMC_DP,
40       FALSE,
41       TRUE,
42       FALSE,
43       0x200,
44       0
45     },
46     {
47       MSG_EMMC_DP,
48       FALSE,
49       TRUE,
50       FALSE,
51       0x200,
52       0
53     },
54     {
55       MSG_EMMC_DP,
56       FALSE,
57       TRUE,
58       FALSE,
59       0x200,
60       0
61     },
62     {
63       MSG_EMMC_DP,
64       FALSE,
65       TRUE,
66       FALSE,
67       0x200,
68       0
69     },
70     {
71       MSG_EMMC_DP,
72       FALSE,
73       TRUE,
74       FALSE,
75       0x200,
76       0
77     },
78     {
79       MSG_EMMC_DP,
80       FALSE,
81       TRUE,
82       FALSE,
83       0x200,
84       0
85     }
86   },
87   0,                              // MediaNum
88   {                               // PartitionType
89     EmmcPartitionUnknown,
90     EmmcPartitionUnknown,
91     EmmcPartitionUnknown,
92     EmmcPartitionUnknown,
93     EmmcPartitionUnknown,
94     EmmcPartitionUnknown,
95     EmmcPartitionUnknown,
96     EmmcPartitionUnknown
97   },
98   0,                              // EmmcHcBase
99   {                               // Capability
100     0,
101   },
102   {                               // Csd
103     0,
104   },
105   {                               // ExtCsd
106     {0},
107   },
108   TRUE,                           // SectorAddressing
109   NULL                            // Private
110 };
111 
112 //
113 // Template for EMMC HC Private Data.
114 //
115 EMMC_PEIM_HC_PRIVATE_DATA gEmmcHcPrivateTemplate = {
116   EMMC_PEIM_SIG,                  // Signature
117   NULL,                           // Pool
118   {                               // BlkIoPpi
119     EmmcBlockIoPeimGetDeviceNo,
120     EmmcBlockIoPeimGetMediaInfo,
121     EmmcBlockIoPeimReadBlocks
122   },
123   {                               // BlkIo2Ppi
124     EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,
125     EmmcBlockIoPeimGetDeviceNo2,
126     EmmcBlockIoPeimGetMediaInfo2,
127     EmmcBlockIoPeimReadBlocks2
128   },
129   {                               // BlkIoPpiList
130     EFI_PEI_PPI_DESCRIPTOR_PPI,
131     &gEfiPeiVirtualBlockIoPpiGuid,
132     NULL
133   },
134   {                               // BlkIo2PpiList
135     EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
136     &gEfiPeiVirtualBlockIo2PpiGuid,
137     NULL
138   },
139   {                               // Slot
140     {
141       0,
142     },
143     {
144       0,
145     },
146     {
147       0,
148     },
149     {
150       0,
151     },
152     {
153       0,
154     },
155     {
156       0,
157     }
158   },
159   0,                              // SlotNum
160   0                               // TotalBlkIoDevices
161 };
162 /**
163   Gets the count of block I/O devices that one specific block driver detects.
164 
165   This function is used for getting the count of block I/O devices that one
166   specific block driver detects.  To the PEI ATAPI driver, it returns the number
167   of all the detected ATAPI devices it detects during the enumeration process.
168   To the PEI legacy floppy driver, it returns the number of all the legacy
169   devices it finds during its enumeration process. If no device is detected,
170   then the function will return zero.
171 
172   @param[in]  PeiServices          General-purpose services that are available
173                                    to every PEIM.
174   @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
175                                    instance.
176   @param[out] NumberBlockDevices   The number of block I/O devices discovered.
177 
178   @retval     EFI_SUCCESS          The operation performed successfully.
179 
180 **/
181 EFI_STATUS
182 EFIAPI
EmmcBlockIoPeimGetDeviceNo(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO_PPI * This,OUT UINTN * NumberBlockDevices)183 EmmcBlockIoPeimGetDeviceNo (
184   IN  EFI_PEI_SERVICES               **PeiServices,
185   IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,
186   OUT UINTN                          *NumberBlockDevices
187   )
188 {
189   EMMC_PEIM_HC_PRIVATE_DATA   *Private;
190 
191   Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
192   *NumberBlockDevices = Private->TotalBlkIoDevices;
193   return EFI_SUCCESS;
194 }
195 
196 /**
197   Gets a block device's media information.
198 
199   This function will provide the caller with the specified block device's media
200   information. If the media changes, calling this function will update the media
201   information accordingly.
202 
203   @param[in]  PeiServices   General-purpose services that are available to every
204                             PEIM
205   @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
206   @param[in]  DeviceIndex   Specifies the block device to which the function wants
207                             to talk. Because the driver that implements Block I/O
208                             PPIs will manage multiple block devices, the PPIs that
209                             want to talk to a single device must specify the
210                             device index that was assigned during the enumeration
211                             process. This index is a number from one to
212                             NumberBlockDevices.
213   @param[out] MediaInfo     The media information of the specified block media.
214                             The caller is responsible for the ownership of this
215                             data structure.
216 
217   @par Note:
218       The MediaInfo structure describes an enumeration of possible block device
219       types.  This enumeration exists because no device paths are actually passed
220       across interfaces that describe the type or class of hardware that is publishing
221       the block I/O interface. This enumeration will allow for policy decisions
222       in the Recovery PEIM, such as "Try to recover from legacy floppy first,
223       LS-120 second, CD-ROM third." If there are multiple partitions abstracted
224       by a given device type, they should be reported in ascending order; this
225       order also applies to nested partitions, such as legacy MBR, where the
226       outermost partitions would have precedence in the reporting order. The
227       same logic applies to systems such as IDE that have precedence relationships
228       like "Master/Slave" or "Primary/Secondary". The master device should be
229       reported first, the slave second.
230 
231   @retval EFI_SUCCESS        Media information about the specified block device
232                              was obtained successfully.
233   @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware
234                              error.
235 
236 **/
237 EFI_STATUS
238 EFIAPI
EmmcBlockIoPeimGetMediaInfo(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO_PPI * This,IN UINTN DeviceIndex,OUT EFI_PEI_BLOCK_IO_MEDIA * MediaInfo)239 EmmcBlockIoPeimGetMediaInfo (
240   IN  EFI_PEI_SERVICES               **PeiServices,
241   IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,
242   IN  UINTN                          DeviceIndex,
243   OUT EFI_PEI_BLOCK_IO_MEDIA         *MediaInfo
244   )
245 {
246   EMMC_PEIM_HC_PRIVATE_DATA          *Private;
247   UINT8                              SlotNum;
248   UINT8                              MediaNum;
249   UINT8                              Location;
250   BOOLEAN                            Found;
251 
252   Found   = FALSE;
253   Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
254 
255   if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {
256     return EFI_INVALID_PARAMETER;
257   }
258 
259   Location = 0;
260   MediaNum = 0;
261   for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {
262     for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {
263       Location ++;
264       if (Location == DeviceIndex) {
265         Found = TRUE;
266         break;
267       }
268     }
269     if (Found) {
270       break;
271     }
272   }
273 
274   MediaInfo->DeviceType   = EMMC;
275   MediaInfo->MediaPresent = TRUE;
276   MediaInfo->LastBlock    = (UINTN)Private->Slot[SlotNum].Media[MediaNum].LastBlock;
277   MediaInfo->BlockSize    = Private->Slot[SlotNum].Media[MediaNum].BlockSize;
278 
279   return EFI_SUCCESS;
280 }
281 
282 /**
283   Reads the requested number of blocks from the specified block device.
284 
285   The function reads the requested number of blocks from the device. All the
286   blocks are read, or an error is returned. If there is no media in the device,
287   the function returns EFI_NO_MEDIA.
288 
289   @param[in]  PeiServices   General-purpose services that are available to
290                             every PEIM.
291   @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
292   @param[in]  DeviceIndex   Specifies the block device to which the function wants
293                             to talk. Because the driver that implements Block I/O
294                             PPIs will manage multiple block devices, PPIs that
295                             want to talk to a single device must specify the device
296                             index that was assigned during the enumeration process.
297                             This index is a number from one to NumberBlockDevices.
298   @param[in]  StartLBA      The starting logical block address (LBA) to read from
299                             on the device
300   @param[in]  BufferSize    The size of the Buffer in bytes. This number must be
301                             a multiple of the intrinsic block size of the device.
302   @param[out] Buffer        A pointer to the destination buffer for the data.
303                             The caller is responsible for the ownership of the
304                             buffer.
305 
306   @retval EFI_SUCCESS             The data was read correctly from the device.
307   @retval EFI_DEVICE_ERROR        The device reported an error while attempting
308                                   to perform the read operation.
309   @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not
310                                   valid, or the buffer is not properly aligned.
311   @retval EFI_NO_MEDIA            There is no media in the device.
312   @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of
313                                   the intrinsic block size of the device.
314 
315 **/
316 EFI_STATUS
317 EFIAPI
EmmcBlockIoPeimReadBlocks(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO_PPI * This,IN UINTN DeviceIndex,IN EFI_PEI_LBA StartLBA,IN UINTN BufferSize,OUT VOID * Buffer)318 EmmcBlockIoPeimReadBlocks (
319   IN  EFI_PEI_SERVICES               **PeiServices,
320   IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,
321   IN  UINTN                          DeviceIndex,
322   IN  EFI_PEI_LBA                    StartLBA,
323   IN  UINTN                          BufferSize,
324   OUT VOID                           *Buffer
325   )
326 {
327   EFI_STATUS                         Status;
328   UINT32                             BlockSize;
329   UINTN                              NumberOfBlocks;
330   EMMC_PEIM_HC_PRIVATE_DATA          *Private;
331   UINT8                              SlotNum;
332   UINT8                              MediaNum;
333   UINT8                              Location;
334   UINT8                              PartitionConfig;
335   UINTN                              Remaining;
336   UINT32                             MaxBlock;
337   BOOLEAN                            Found;
338 
339   Status  = EFI_SUCCESS;
340   Found   = FALSE;
341   Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
342 
343   //
344   // Check parameters
345   //
346   if (Buffer == NULL) {
347     return EFI_INVALID_PARAMETER;
348   }
349 
350   if (BufferSize == 0) {
351     return EFI_SUCCESS;
352   }
353 
354   if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {
355     return EFI_INVALID_PARAMETER;
356   }
357 
358   Location = 0;
359   MediaNum = 0;
360   for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {
361     for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {
362       Location ++;
363       if (Location == DeviceIndex) {
364         Found = TRUE;
365         break;
366       }
367     }
368     if (Found) {
369       break;
370     }
371   }
372 
373   BlockSize = Private->Slot[SlotNum].Media[MediaNum].BlockSize;
374   if (BufferSize % BlockSize != 0) {
375     return EFI_BAD_BUFFER_SIZE;
376   }
377 
378   if (StartLBA > Private->Slot[SlotNum].Media[MediaNum].LastBlock) {
379     return EFI_INVALID_PARAMETER;
380   }
381 
382   NumberOfBlocks = BufferSize / BlockSize;
383 
384   //
385   // Check if needs to switch partition access.
386   //
387   PartitionConfig = Private->Slot[SlotNum].ExtCsd.PartitionConfig;
388   if ((PartitionConfig & 0x7) != Private->Slot[SlotNum].PartitionType[MediaNum]) {
389     PartitionConfig &= (UINT8)~0x7;
390     PartitionConfig |= Private->Slot[SlotNum].PartitionType[MediaNum];
391     Status = EmmcPeimSwitch (
392                &Private->Slot[SlotNum],
393                0x3,
394                OFFSET_OF (EMMC_EXT_CSD, PartitionConfig),
395                PartitionConfig,
396                0x0
397                );
398     if (EFI_ERROR (Status)) {
399       return Status;
400     }
401     Private->Slot[SlotNum].ExtCsd.PartitionConfig = PartitionConfig;
402   }
403   //
404   // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
405   //
406   Remaining = NumberOfBlocks;
407   MaxBlock  = 0xFFFF;
408 
409   while (Remaining > 0) {
410     if (Remaining <= MaxBlock) {
411       NumberOfBlocks = Remaining;
412     } else {
413       NumberOfBlocks = MaxBlock;
414     }
415 
416     Status = EmmcPeimSetBlkCount (&Private->Slot[SlotNum], (UINT16)NumberOfBlocks);
417     if (EFI_ERROR (Status)) {
418       return Status;
419     }
420 
421     BufferSize = NumberOfBlocks * BlockSize;
422     Status = EmmcPeimRwMultiBlocks (&Private->Slot[SlotNum], StartLBA, BlockSize, Buffer, BufferSize, TRUE);
423     if (EFI_ERROR (Status)) {
424       return Status;
425     }
426 
427     StartLBA  += NumberOfBlocks;
428     Buffer     = (UINT8*)Buffer + BufferSize;
429     Remaining -= NumberOfBlocks;
430   }
431   return Status;
432 }
433 
434 /**
435   Gets the count of block I/O devices that one specific block driver detects.
436 
437   This function is used for getting the count of block I/O devices that one
438   specific block driver detects.  To the PEI ATAPI driver, it returns the number
439   of all the detected ATAPI devices it detects during the enumeration process.
440   To the PEI legacy floppy driver, it returns the number of all the legacy
441   devices it finds during its enumeration process. If no device is detected,
442   then the function will return zero.
443 
444   @param[in]  PeiServices          General-purpose services that are available
445                                    to every PEIM.
446   @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
447                                    instance.
448   @param[out] NumberBlockDevices   The number of block I/O devices discovered.
449 
450   @retval     EFI_SUCCESS          The operation performed successfully.
451 
452 **/
453 EFI_STATUS
454 EFIAPI
EmmcBlockIoPeimGetDeviceNo2(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI * This,OUT UINTN * NumberBlockDevices)455 EmmcBlockIoPeimGetDeviceNo2 (
456   IN  EFI_PEI_SERVICES               **PeiServices,
457   IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
458   OUT UINTN                          *NumberBlockDevices
459   )
460 {
461   EMMC_PEIM_HC_PRIVATE_DATA   *Private;
462 
463   Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
464   *NumberBlockDevices = Private->TotalBlkIoDevices;
465 
466   return EFI_SUCCESS;
467 }
468 
469 /**
470   Gets a block device's media information.
471 
472   This function will provide the caller with the specified block device's media
473   information. If the media changes, calling this function will update the media
474   information accordingly.
475 
476   @param[in]  PeiServices   General-purpose services that are available to every
477                             PEIM
478   @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
479   @param[in]  DeviceIndex   Specifies the block device to which the function wants
480                             to talk. Because the driver that implements Block I/O
481                             PPIs will manage multiple block devices, the PPIs that
482                             want to talk to a single device must specify the
483                             device index that was assigned during the enumeration
484                             process. This index is a number from one to
485                             NumberBlockDevices.
486   @param[out] MediaInfo     The media information of the specified block media.
487                             The caller is responsible for the ownership of this
488                             data structure.
489 
490   @par Note:
491       The MediaInfo structure describes an enumeration of possible block device
492       types.  This enumeration exists because no device paths are actually passed
493       across interfaces that describe the type or class of hardware that is publishing
494       the block I/O interface. This enumeration will allow for policy decisions
495       in the Recovery PEIM, such as "Try to recover from legacy floppy first,
496       LS-120 second, CD-ROM third." If there are multiple partitions abstracted
497       by a given device type, they should be reported in ascending order; this
498       order also applies to nested partitions, such as legacy MBR, where the
499       outermost partitions would have precedence in the reporting order. The
500       same logic applies to systems such as IDE that have precedence relationships
501       like "Master/Slave" or "Primary/Secondary". The master device should be
502       reported first, the slave second.
503 
504   @retval EFI_SUCCESS        Media information about the specified block device
505                              was obtained successfully.
506   @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware
507                              error.
508 
509 **/
510 EFI_STATUS
511 EFIAPI
EmmcBlockIoPeimGetMediaInfo2(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI * This,IN UINTN DeviceIndex,OUT EFI_PEI_BLOCK_IO2_MEDIA * MediaInfo)512 EmmcBlockIoPeimGetMediaInfo2 (
513   IN  EFI_PEI_SERVICES               **PeiServices,
514   IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
515   IN  UINTN                          DeviceIndex,
516   OUT EFI_PEI_BLOCK_IO2_MEDIA        *MediaInfo
517   )
518 {
519   EFI_STATUS                         Status;
520   EMMC_PEIM_HC_PRIVATE_DATA          *Private;
521   EFI_PEI_BLOCK_IO_MEDIA             Media;
522   UINT8                              SlotNum;
523   UINT8                              MediaNum;
524   UINT8                              Location;
525   BOOLEAN                            Found;
526 
527   Found   = FALSE;
528   Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
529 
530   Status  = EmmcBlockIoPeimGetMediaInfo (
531               PeiServices,
532               &Private->BlkIoPpi,
533               DeviceIndex,
534               &Media
535               );
536   if (EFI_ERROR (Status)) {
537     return Status;
538   }
539 
540   Location = 0;
541   MediaNum = 0;
542   for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {
543     for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {
544       Location ++;
545       if (Location == DeviceIndex) {
546         Found = TRUE;
547         break;
548       }
549     }
550     if (Found) {
551       break;
552     }
553   }
554 
555   CopyMem (MediaInfo, &(Private->Slot[SlotNum].Media[MediaNum]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA));
556   return EFI_SUCCESS;
557 }
558 
559 /**
560   Reads the requested number of blocks from the specified block device.
561 
562   The function reads the requested number of blocks from the device. All the
563   blocks are read, or an error is returned. If there is no media in the device,
564   the function returns EFI_NO_MEDIA.
565 
566   @param[in]  PeiServices   General-purpose services that are available to
567                             every PEIM.
568   @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
569   @param[in]  DeviceIndex   Specifies the block device to which the function wants
570                             to talk. Because the driver that implements Block I/O
571                             PPIs will manage multiple block devices, PPIs that
572                             want to talk to a single device must specify the device
573                             index that was assigned during the enumeration process.
574                             This index is a number from one to NumberBlockDevices.
575   @param[in]  StartLBA      The starting logical block address (LBA) to read from
576                             on the device
577   @param[in]  BufferSize    The size of the Buffer in bytes. This number must be
578                             a multiple of the intrinsic block size of the device.
579   @param[out] Buffer        A pointer to the destination buffer for the data.
580                             The caller is responsible for the ownership of the
581                             buffer.
582 
583   @retval EFI_SUCCESS             The data was read correctly from the device.
584   @retval EFI_DEVICE_ERROR        The device reported an error while attempting
585                                   to perform the read operation.
586   @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not
587                                   valid, or the buffer is not properly aligned.
588   @retval EFI_NO_MEDIA            There is no media in the device.
589   @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of
590                                   the intrinsic block size of the device.
591 
592 **/
593 EFI_STATUS
594 EFIAPI
EmmcBlockIoPeimReadBlocks2(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI * This,IN UINTN DeviceIndex,IN EFI_PEI_LBA StartLBA,IN UINTN BufferSize,OUT VOID * Buffer)595 EmmcBlockIoPeimReadBlocks2 (
596   IN  EFI_PEI_SERVICES               **PeiServices,
597   IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
598   IN  UINTN                          DeviceIndex,
599   IN  EFI_PEI_LBA                    StartLBA,
600   IN  UINTN                          BufferSize,
601   OUT VOID                           *Buffer
602   )
603 {
604   EFI_STATUS                         Status;
605   EMMC_PEIM_HC_PRIVATE_DATA          *Private;
606 
607   Status    = EFI_SUCCESS;
608   Private   = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
609 
610   Status  = EmmcBlockIoPeimReadBlocks (
611               PeiServices,
612               &Private->BlkIoPpi,
613               DeviceIndex,
614               StartLBA,
615               BufferSize,
616               Buffer
617               );
618   return Status;
619 }
620 
621 /**
622   The user code starts with this function.
623 
624   @param  FileHandle             Handle of the file being invoked.
625   @param  PeiServices            Describes the list of possible PEI Services.
626 
627   @retval EFI_SUCCESS            The driver is successfully initialized.
628   @retval Others                 Can't initialize the driver.
629 
630 **/
631 EFI_STATUS
632 EFIAPI
InitializeEmmcBlockIoPeim(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)633 InitializeEmmcBlockIoPeim (
634   IN EFI_PEI_FILE_HANDLE        FileHandle,
635   IN CONST EFI_PEI_SERVICES     **PeiServices
636   )
637 {
638   EFI_STATUS                       Status;
639   EMMC_PEIM_HC_PRIVATE_DATA        *Private;
640   EDKII_SD_MMC_HOST_CONTROLLER_PPI *SdMmcHcPpi;
641   UINT32                           Index;
642   UINT32                           PartitionIndex;
643   UINTN                            *MmioBase;
644   UINT8                            BarNum;
645   UINT8                            SlotNum;
646   UINT8                            MediaNum;
647   UINT8                            Controller;
648   UINT64                           Capacity;
649   EMMC_EXT_CSD                     *ExtCsd;
650   EMMC_HC_SLOT_CAP                 Capability;
651   EMMC_PEIM_HC_SLOT                *Slot;
652   UINT32                           SecCount;
653   UINT32                           GpSizeMult;
654 
655   //
656   // Shadow this PEIM to run from memory
657   //
658   if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
659     return EFI_SUCCESS;
660   }
661 
662   //
663   // locate Emmc host controller PPI
664   //
665   Status = PeiServicesLocatePpi (
666              &gEdkiiPeiSdMmcHostControllerPpiGuid,
667              0,
668              NULL,
669              (VOID **) &SdMmcHcPpi
670              );
671   if (EFI_ERROR (Status)) {
672     return EFI_DEVICE_ERROR;
673   }
674 
675   Controller = 0;
676   MmioBase   = NULL;
677   while (TRUE) {
678     Status = SdMmcHcPpi->GetSdMmcHcMmioBar (SdMmcHcPpi, Controller, &MmioBase, &BarNum);
679     //
680     // When status is error, meant no controller is found
681     //
682     if (EFI_ERROR (Status)) {
683       break;
684     }
685 
686     if (BarNum == 0) {
687       Controller++;
688       continue;
689     }
690 
691     Private = AllocateCopyPool (sizeof (EMMC_PEIM_HC_PRIVATE_DATA), &gEmmcHcPrivateTemplate);
692     if (Private == NULL) {
693       Status = EFI_OUT_OF_RESOURCES;
694       break;
695     }
696     Private->BlkIoPpiList.Ppi  = (VOID*)&Private->BlkIoPpi;
697     Private->BlkIo2PpiList.Ppi = (VOID*)&Private->BlkIo2Ppi;
698     //
699     // Initialize the memory pool which will be used in all transactions.
700     //
701     Status = EmmcPeimInitMemPool (Private);
702     if (EFI_ERROR (Status)) {
703       Status = EFI_OUT_OF_RESOURCES;
704       break;
705     }
706 
707     for (Index = 0; Index < BarNum; Index++) {
708       Status = EmmcPeimHcGetCapability (MmioBase[Index], &Capability);
709       if (EFI_ERROR (Status)) {
710         continue;
711       }
712       if (Capability.SlotType != 0x1) {
713         DEBUG ((EFI_D_INFO, "The slot at 0x%x is not embedded slot type\n", MmioBase[Index]));
714         Status = EFI_UNSUPPORTED;
715         continue;
716       }
717 
718       Status = EmmcPeimHcReset (MmioBase[Index]);
719       if (EFI_ERROR (Status)) {
720         continue;
721       }
722       Status = EmmcPeimHcCardDetect (MmioBase[Index]);
723       if (EFI_ERROR (Status)) {
724         continue;
725       }
726       Status = EmmcPeimHcInitHost (MmioBase[Index]);
727       if (EFI_ERROR (Status)) {
728         continue;
729       }
730 
731       SlotNum = Private->SlotNum;
732       Slot    = &Private->Slot[SlotNum];
733       CopyMem (Slot, &gEmmcHcSlotTemplate, sizeof (EMMC_PEIM_HC_SLOT));
734       Slot->Private    = Private;
735       Slot->EmmcHcBase = MmioBase[Index];
736       CopyMem (&Slot->Capability, &Capability, sizeof (Capability));
737 
738       Status = EmmcPeimIdentification (Slot);
739       if (EFI_ERROR (Status)) {
740         continue;
741       }
742 
743       ExtCsd = &Slot->ExtCsd;
744       if (ExtCsd->ExtCsdRev < 5) {
745         DEBUG ((EFI_D_ERROR, "The EMMC device version is too low, we don't support!!!\n"));
746         Status = EFI_UNSUPPORTED;
747         continue;
748       }
749       if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) {
750         DEBUG ((EFI_D_ERROR, "The EMMC device doesn't support Partition Feature!!!\n"));
751         Status = EFI_UNSUPPORTED;
752         continue;
753       }
754 
755       for (PartitionIndex = 0; PartitionIndex < EMMC_PEIM_MAX_PARTITIONS; PartitionIndex++) {
756         switch (PartitionIndex) {
757           case EmmcPartitionUserData:
758             SecCount = *(UINT32*)&ExtCsd->SecCount;
759             Capacity = MultU64x32 ((UINT64)SecCount, 0x200);
760             break;
761           case EmmcPartitionBoot1:
762           case EmmcPartitionBoot2:
763             Capacity = ExtCsd->BootSizeMult * SIZE_128KB;
764             break;
765           case EmmcPartitionRPMB:
766             Capacity = ExtCsd->RpmbSizeMult * SIZE_128KB;
767             break;
768           case EmmcPartitionGP1:
769             GpSizeMult = (ExtCsd->GpSizeMult[0] | (ExtCsd->GpSizeMult[1] << 8) | (ExtCsd->GpSizeMult[2] << 16));
770             Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
771             break;
772           case EmmcPartitionGP2:
773             GpSizeMult = (ExtCsd->GpSizeMult[3] | (ExtCsd->GpSizeMult[4] << 8) | (ExtCsd->GpSizeMult[5] << 16));
774             Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
775             break;
776           case EmmcPartitionGP3:
777             GpSizeMult = (ExtCsd->GpSizeMult[6] | (ExtCsd->GpSizeMult[7] << 8) | (ExtCsd->GpSizeMult[8] << 16));
778             Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
779             break;
780           case EmmcPartitionGP4:
781             GpSizeMult = (ExtCsd->GpSizeMult[9] | (ExtCsd->GpSizeMult[10] << 8) | (ExtCsd->GpSizeMult[11] << 16));
782             Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
783             break;
784           default:
785             ASSERT (FALSE);
786             continue;
787         }
788 
789         MediaNum = Slot->MediaNum;
790         if (Capacity != 0) {
791           Slot->Media[MediaNum].LastBlock = DivU64x32 (Capacity, Slot->Media[MediaNum].BlockSize) - 1;
792           Slot->PartitionType[MediaNum] = PartitionIndex;
793           Private->TotalBlkIoDevices++;
794           Slot->MediaNum++;
795         }
796       }
797       Private->SlotNum++;
798     }
799     Controller++;
800 
801     if (!EFI_ERROR (Status)) {
802       PeiServicesInstallPpi (&Private->BlkIoPpiList);
803     }
804   }
805 
806   return EFI_SUCCESS;
807 }
808