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