]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.c
MdeModulePkg: Change use of EFI_D_* to DEBUG_*
[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 Gets the count of block I/O devices that one specific block driver detects.
163
164 This function is used for getting the count of block I/O devices that one
165 specific block driver detects. To the PEI ATAPI driver, it returns the number
166 of all the detected ATAPI devices it detects during the enumeration process.
167 To the PEI legacy floppy driver, it returns the number of all the legacy
168 devices it finds during its enumeration process. If no device is detected,
169 then the function will return zero.
170
171 @param[in] PeiServices General-purpose services that are available
172 to every PEIM.
173 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
174 instance.
175 @param[out] NumberBlockDevices The number of block I/O devices discovered.
176
177 @retval EFI_SUCCESS The operation performed successfully.
178
179 **/
180 EFI_STATUS
181 EFIAPI
182 EmmcBlockIoPeimGetDeviceNo (
183 IN EFI_PEI_SERVICES **PeiServices,
184 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
185 OUT UINTN *NumberBlockDevices
186 )
187 {
188 EMMC_PEIM_HC_PRIVATE_DATA *Private;
189
190 Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
191 *NumberBlockDevices = Private->TotalBlkIoDevices;
192 return EFI_SUCCESS;
193 }
194
195 /**
196 Gets a block device's media information.
197
198 This function will provide the caller with the specified block device's media
199 information. If the media changes, calling this function will update the media
200 information accordingly.
201
202 @param[in] PeiServices General-purpose services that are available to every
203 PEIM
204 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
205 @param[in] DeviceIndex Specifies the block device to which the function wants
206 to talk. Because the driver that implements Block I/O
207 PPIs will manage multiple block devices, the PPIs that
208 want to talk to a single device must specify the
209 device index that was assigned during the enumeration
210 process. This index is a number from one to
211 NumberBlockDevices.
212 @param[out] MediaInfo The media information of the specified block media.
213 The caller is responsible for the ownership of this
214 data structure.
215
216 @par Note:
217 The MediaInfo structure describes an enumeration of possible block device
218 types. This enumeration exists because no device paths are actually passed
219 across interfaces that describe the type or class of hardware that is publishing
220 the block I/O interface. This enumeration will allow for policy decisions
221 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
222 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
223 by a given device type, they should be reported in ascending order; this
224 order also applies to nested partitions, such as legacy MBR, where the
225 outermost partitions would have precedence in the reporting order. The
226 same logic applies to systems such as IDE that have precedence relationships
227 like "Master/Slave" or "Primary/Secondary". The master device should be
228 reported first, the slave second.
229
230 @retval EFI_SUCCESS Media information about the specified block device
231 was obtained successfully.
232 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
233 error.
234
235 **/
236 EFI_STATUS
237 EFIAPI
238 EmmcBlockIoPeimGetMediaInfo (
239 IN EFI_PEI_SERVICES **PeiServices,
240 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
241 IN UINTN DeviceIndex,
242 OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
243 )
244 {
245 EMMC_PEIM_HC_PRIVATE_DATA *Private;
246 UINT8 SlotNum;
247 UINT8 MediaNum;
248 UINT8 Location;
249 BOOLEAN Found;
250
251 Found = FALSE;
252 Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
253
254 if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {
255 return EFI_INVALID_PARAMETER;
256 }
257
258 Location = 0;
259 MediaNum = 0;
260 for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {
261 for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {
262 Location ++;
263 if (Location == DeviceIndex) {
264 Found = TRUE;
265 break;
266 }
267 }
268 if (Found) {
269 break;
270 }
271 }
272
273 MediaInfo->DeviceType = EMMC;
274 MediaInfo->MediaPresent = TRUE;
275 MediaInfo->LastBlock = (UINTN)Private->Slot[SlotNum].Media[MediaNum].LastBlock;
276 MediaInfo->BlockSize = Private->Slot[SlotNum].Media[MediaNum].BlockSize;
277
278 return EFI_SUCCESS;
279 }
280
281 /**
282 Reads the requested number of blocks from the specified block device.
283
284 The function reads the requested number of blocks from the device. All the
285 blocks are read, or an error is returned. If there is no media in the device,
286 the function returns EFI_NO_MEDIA.
287
288 @param[in] PeiServices General-purpose services that are available to
289 every PEIM.
290 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
291 @param[in] DeviceIndex Specifies the block device to which the function wants
292 to talk. Because the driver that implements Block I/O
293 PPIs will manage multiple block devices, PPIs that
294 want to talk to a single device must specify the device
295 index that was assigned during the enumeration process.
296 This index is a number from one to NumberBlockDevices.
297 @param[in] StartLBA The starting logical block address (LBA) to read from
298 on the device
299 @param[in] BufferSize The size of the Buffer in bytes. This number must be
300 a multiple of the intrinsic block size of the device.
301 @param[out] Buffer A pointer to the destination buffer for the data.
302 The caller is responsible for the ownership of the
303 buffer.
304
305 @retval EFI_SUCCESS The data was read correctly from the device.
306 @retval EFI_DEVICE_ERROR The device reported an error while attempting
307 to perform the read operation.
308 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
309 valid, or the buffer is not properly aligned.
310 @retval EFI_NO_MEDIA There is no media in the device.
311 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
312 the intrinsic block size of the device.
313
314 **/
315 EFI_STATUS
316 EFIAPI
317 EmmcBlockIoPeimReadBlocks (
318 IN EFI_PEI_SERVICES **PeiServices,
319 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
320 IN UINTN DeviceIndex,
321 IN EFI_PEI_LBA StartLBA,
322 IN UINTN BufferSize,
323 OUT VOID *Buffer
324 )
325 {
326 EFI_STATUS Status;
327 UINT32 BlockSize;
328 UINTN NumberOfBlocks;
329 EMMC_PEIM_HC_PRIVATE_DATA *Private;
330 UINT8 SlotNum;
331 UINT8 MediaNum;
332 UINT8 Location;
333 UINT8 PartitionConfig;
334 UINTN Remaining;
335 UINT32 MaxBlock;
336 BOOLEAN Found;
337
338 Status = EFI_SUCCESS;
339 Found = FALSE;
340 Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
341
342 //
343 // Check parameters
344 //
345 if (Buffer == NULL) {
346 return EFI_INVALID_PARAMETER;
347 }
348
349 if (BufferSize == 0) {
350 return EFI_SUCCESS;
351 }
352
353 if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {
354 return EFI_INVALID_PARAMETER;
355 }
356
357 Location = 0;
358 MediaNum = 0;
359 for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {
360 for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {
361 Location ++;
362 if (Location == DeviceIndex) {
363 Found = TRUE;
364 break;
365 }
366 }
367 if (Found) {
368 break;
369 }
370 }
371
372 BlockSize = Private->Slot[SlotNum].Media[MediaNum].BlockSize;
373 if (BufferSize % BlockSize != 0) {
374 return EFI_BAD_BUFFER_SIZE;
375 }
376
377 if (StartLBA > Private->Slot[SlotNum].Media[MediaNum].LastBlock) {
378 return EFI_INVALID_PARAMETER;
379 }
380
381 NumberOfBlocks = BufferSize / BlockSize;
382
383 //
384 // Check if needs to switch partition access.
385 //
386 PartitionConfig = Private->Slot[SlotNum].ExtCsd.PartitionConfig;
387 if ((PartitionConfig & 0x7) != Private->Slot[SlotNum].PartitionType[MediaNum]) {
388 PartitionConfig &= (UINT8)~0x7;
389 PartitionConfig |= Private->Slot[SlotNum].PartitionType[MediaNum];
390 Status = EmmcPeimSwitch (
391 &Private->Slot[SlotNum],
392 0x3,
393 OFFSET_OF (EMMC_EXT_CSD, PartitionConfig),
394 PartitionConfig,
395 0x0
396 );
397 if (EFI_ERROR (Status)) {
398 return Status;
399 }
400 Private->Slot[SlotNum].ExtCsd.PartitionConfig = PartitionConfig;
401 }
402 //
403 // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
404 //
405 Remaining = NumberOfBlocks;
406 MaxBlock = 0xFFFF;
407
408 while (Remaining > 0) {
409 if (Remaining <= MaxBlock) {
410 NumberOfBlocks = Remaining;
411 } else {
412 NumberOfBlocks = MaxBlock;
413 }
414
415 Status = EmmcPeimSetBlkCount (&Private->Slot[SlotNum], (UINT16)NumberOfBlocks);
416 if (EFI_ERROR (Status)) {
417 return Status;
418 }
419
420 BufferSize = NumberOfBlocks * BlockSize;
421 Status = EmmcPeimRwMultiBlocks (&Private->Slot[SlotNum], StartLBA, BlockSize, Buffer, BufferSize, TRUE);
422 if (EFI_ERROR (Status)) {
423 return Status;
424 }
425
426 StartLBA += NumberOfBlocks;
427 Buffer = (UINT8*)Buffer + BufferSize;
428 Remaining -= NumberOfBlocks;
429 }
430 return Status;
431 }
432
433 /**
434 Gets the count of block I/O devices that one specific block driver detects.
435
436 This function is used for getting the count of block I/O devices that one
437 specific block driver detects. To the PEI ATAPI driver, it returns the number
438 of all the detected ATAPI devices it detects during the enumeration process.
439 To the PEI legacy floppy driver, it returns the number of all the legacy
440 devices it finds during its enumeration process. If no device is detected,
441 then the function will return zero.
442
443 @param[in] PeiServices General-purpose services that are available
444 to every PEIM.
445 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
446 instance.
447 @param[out] NumberBlockDevices The number of block I/O devices discovered.
448
449 @retval EFI_SUCCESS The operation performed successfully.
450
451 **/
452 EFI_STATUS
453 EFIAPI
454 EmmcBlockIoPeimGetDeviceNo2 (
455 IN EFI_PEI_SERVICES **PeiServices,
456 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
457 OUT UINTN *NumberBlockDevices
458 )
459 {
460 EMMC_PEIM_HC_PRIVATE_DATA *Private;
461
462 Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
463 *NumberBlockDevices = Private->TotalBlkIoDevices;
464
465 return EFI_SUCCESS;
466 }
467
468 /**
469 Gets a block device's media information.
470
471 This function will provide the caller with the specified block device's media
472 information. If the media changes, calling this function will update the media
473 information accordingly.
474
475 @param[in] PeiServices General-purpose services that are available to every
476 PEIM
477 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
478 @param[in] DeviceIndex Specifies the block device to which the function wants
479 to talk. Because the driver that implements Block I/O
480 PPIs will manage multiple block devices, the PPIs that
481 want to talk to a single device must specify the
482 device index that was assigned during the enumeration
483 process. This index is a number from one to
484 NumberBlockDevices.
485 @param[out] MediaInfo The media information of the specified block media.
486 The caller is responsible for the ownership of this
487 data structure.
488
489 @par Note:
490 The MediaInfo structure describes an enumeration of possible block device
491 types. This enumeration exists because no device paths are actually passed
492 across interfaces that describe the type or class of hardware that is publishing
493 the block I/O interface. This enumeration will allow for policy decisions
494 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
495 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
496 by a given device type, they should be reported in ascending order; this
497 order also applies to nested partitions, such as legacy MBR, where the
498 outermost partitions would have precedence in the reporting order. The
499 same logic applies to systems such as IDE that have precedence relationships
500 like "Master/Slave" or "Primary/Secondary". The master device should be
501 reported first, the slave second.
502
503 @retval EFI_SUCCESS Media information about the specified block device
504 was obtained successfully.
505 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
506 error.
507
508 **/
509 EFI_STATUS
510 EFIAPI
511 EmmcBlockIoPeimGetMediaInfo2 (
512 IN EFI_PEI_SERVICES **PeiServices,
513 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
514 IN UINTN DeviceIndex,
515 OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
516 )
517 {
518 EFI_STATUS Status;
519 EMMC_PEIM_HC_PRIVATE_DATA *Private;
520 EFI_PEI_BLOCK_IO_MEDIA Media;
521 UINT8 SlotNum;
522 UINT8 MediaNum;
523 UINT8 Location;
524 BOOLEAN Found;
525
526 Found = FALSE;
527 Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
528
529 Status = EmmcBlockIoPeimGetMediaInfo (
530 PeiServices,
531 &Private->BlkIoPpi,
532 DeviceIndex,
533 &Media
534 );
535 if (EFI_ERROR (Status)) {
536 return Status;
537 }
538
539 Location = 0;
540 MediaNum = 0;
541 for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {
542 for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {
543 Location ++;
544 if (Location == DeviceIndex) {
545 Found = TRUE;
546 break;
547 }
548 }
549 if (Found) {
550 break;
551 }
552 }
553
554 CopyMem (MediaInfo, &(Private->Slot[SlotNum].Media[MediaNum]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA));
555 return EFI_SUCCESS;
556 }
557
558 /**
559 Reads the requested number of blocks from the specified block device.
560
561 The function reads the requested number of blocks from the device. All the
562 blocks are read, or an error is returned. If there is no media in the device,
563 the function returns EFI_NO_MEDIA.
564
565 @param[in] PeiServices General-purpose services that are available to
566 every PEIM.
567 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
568 @param[in] DeviceIndex Specifies the block device to which the function wants
569 to talk. Because the driver that implements Block I/O
570 PPIs will manage multiple block devices, PPIs that
571 want to talk to a single device must specify the device
572 index that was assigned during the enumeration process.
573 This index is a number from one to NumberBlockDevices.
574 @param[in] StartLBA The starting logical block address (LBA) to read from
575 on the device
576 @param[in] BufferSize The size of the Buffer in bytes. This number must be
577 a multiple of the intrinsic block size of the device.
578 @param[out] Buffer A pointer to the destination buffer for the data.
579 The caller is responsible for the ownership of the
580 buffer.
581
582 @retval EFI_SUCCESS The data was read correctly from the device.
583 @retval EFI_DEVICE_ERROR The device reported an error while attempting
584 to perform the read operation.
585 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
586 valid, or the buffer is not properly aligned.
587 @retval EFI_NO_MEDIA There is no media in the device.
588 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
589 the intrinsic block size of the device.
590
591 **/
592 EFI_STATUS
593 EFIAPI
594 EmmcBlockIoPeimReadBlocks2 (
595 IN EFI_PEI_SERVICES **PeiServices,
596 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
597 IN UINTN DeviceIndex,
598 IN EFI_PEI_LBA StartLBA,
599 IN UINTN BufferSize,
600 OUT VOID *Buffer
601 )
602 {
603 EFI_STATUS Status;
604 EMMC_PEIM_HC_PRIVATE_DATA *Private;
605
606 Status = EFI_SUCCESS;
607 Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
608
609 Status = EmmcBlockIoPeimReadBlocks (
610 PeiServices,
611 &Private->BlkIoPpi,
612 DeviceIndex,
613 StartLBA,
614 BufferSize,
615 Buffer
616 );
617 return Status;
618 }
619
620 /**
621 One notified function to cleanup the allocated DMA buffers at the end of PEI.
622
623 @param[in] PeiServices Pointer to PEI Services Table.
624 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
625 event that caused this function to execute.
626 @param[in] Ppi Pointer to the PPI data associated with this function.
627
628 @retval EFI_SUCCESS The function completes successfully
629
630 **/
631 EFI_STATUS
632 EFIAPI
633 EmmcBlockIoPeimEndOfPei (
634 IN EFI_PEI_SERVICES **PeiServices,
635 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
636 IN VOID *Ppi
637 )
638 {
639 EMMC_PEIM_HC_PRIVATE_DATA *Private;
640
641 Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);
642
643 if ((Private->Pool != NULL) && (Private->Pool->Head != NULL)) {
644 EmmcPeimFreeMemPool (Private->Pool);
645 }
646
647 return EFI_SUCCESS;
648 }
649
650 /**
651 The user code starts with this function.
652
653 @param FileHandle Handle of the file being invoked.
654 @param PeiServices Describes the list of possible PEI Services.
655
656 @retval EFI_SUCCESS The driver is successfully initialized.
657 @retval Others Can't initialize the driver.
658
659 **/
660 EFI_STATUS
661 EFIAPI
662 InitializeEmmcBlockIoPeim (
663 IN EFI_PEI_FILE_HANDLE FileHandle,
664 IN CONST EFI_PEI_SERVICES **PeiServices
665 )
666 {
667 EFI_STATUS Status;
668 EMMC_PEIM_HC_PRIVATE_DATA *Private;
669 EDKII_SD_MMC_HOST_CONTROLLER_PPI *SdMmcHcPpi;
670 UINT32 Index;
671 UINT32 PartitionIndex;
672 UINTN *MmioBase;
673 UINT8 BarNum;
674 UINT8 SlotNum;
675 UINT8 MediaNum;
676 UINT8 Controller;
677 UINT64 Capacity;
678 EMMC_EXT_CSD *ExtCsd;
679 EMMC_HC_SLOT_CAP Capability;
680 EMMC_PEIM_HC_SLOT *Slot;
681 UINT32 SecCount;
682 UINT32 GpSizeMult;
683
684 //
685 // Shadow this PEIM to run from memory
686 //
687 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
688 return EFI_SUCCESS;
689 }
690
691 //
692 // locate Emmc host controller PPI
693 //
694 Status = PeiServicesLocatePpi (
695 &gEdkiiPeiSdMmcHostControllerPpiGuid,
696 0,
697 NULL,
698 (VOID **) &SdMmcHcPpi
699 );
700 if (EFI_ERROR (Status)) {
701 return EFI_DEVICE_ERROR;
702 }
703
704 IoMmuInit ();
705
706 Controller = 0;
707 MmioBase = NULL;
708 while (TRUE) {
709 Status = SdMmcHcPpi->GetSdMmcHcMmioBar (SdMmcHcPpi, Controller, &MmioBase, &BarNum);
710 //
711 // When status is error, meant no controller is found
712 //
713 if (EFI_ERROR (Status)) {
714 break;
715 }
716
717 if (BarNum == 0) {
718 Controller++;
719 continue;
720 }
721
722 Private = AllocateCopyPool (sizeof (EMMC_PEIM_HC_PRIVATE_DATA), &gEmmcHcPrivateTemplate);
723 if (Private == NULL) {
724 Status = EFI_OUT_OF_RESOURCES;
725 break;
726 }
727 Private->BlkIoPpiList.Ppi = (VOID*)&Private->BlkIoPpi;
728 Private->BlkIo2PpiList.Ppi = (VOID*)&Private->BlkIo2Ppi;
729 //
730 // Initialize the memory pool which will be used in all transactions.
731 //
732 Status = EmmcPeimInitMemPool (Private);
733 if (EFI_ERROR (Status)) {
734 Status = EFI_OUT_OF_RESOURCES;
735 break;
736 }
737
738 for (Index = 0; Index < BarNum; Index++) {
739 Status = EmmcPeimHcGetCapability (MmioBase[Index], &Capability);
740 if (EFI_ERROR (Status)) {
741 continue;
742 }
743 if (Capability.SlotType != 0x1) {
744 DEBUG ((DEBUG_INFO, "The slot at 0x%x is not embedded slot type\n", MmioBase[Index]));
745 Status = EFI_UNSUPPORTED;
746 continue;
747 }
748
749 Status = EmmcPeimHcReset (MmioBase[Index]);
750 if (EFI_ERROR (Status)) {
751 continue;
752 }
753 Status = EmmcPeimHcCardDetect (MmioBase[Index]);
754 if (EFI_ERROR (Status)) {
755 continue;
756 }
757 Status = EmmcPeimHcInitHost (MmioBase[Index]);
758 if (EFI_ERROR (Status)) {
759 continue;
760 }
761
762 SlotNum = Private->SlotNum;
763 Slot = &Private->Slot[SlotNum];
764 CopyMem (Slot, &gEmmcHcSlotTemplate, sizeof (EMMC_PEIM_HC_SLOT));
765 Slot->Private = Private;
766 Slot->EmmcHcBase = MmioBase[Index];
767 CopyMem (&Slot->Capability, &Capability, sizeof (Capability));
768
769 Status = EmmcPeimIdentification (Slot);
770 if (EFI_ERROR (Status)) {
771 continue;
772 }
773
774 ExtCsd = &Slot->ExtCsd;
775 if (ExtCsd->ExtCsdRev < 5) {
776 DEBUG ((DEBUG_ERROR, "The EMMC device version is too low, we don't support!!!\n"));
777 Status = EFI_UNSUPPORTED;
778 continue;
779 }
780 if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) {
781 DEBUG ((DEBUG_ERROR, "The EMMC device doesn't support Partition Feature!!!\n"));
782 Status = EFI_UNSUPPORTED;
783 continue;
784 }
785
786 for (PartitionIndex = 0; PartitionIndex < EMMC_PEIM_MAX_PARTITIONS; PartitionIndex++) {
787 switch (PartitionIndex) {
788 case EmmcPartitionUserData:
789 SecCount = *(UINT32*)&ExtCsd->SecCount;
790 Capacity = MultU64x32 ((UINT64)SecCount, 0x200);
791 break;
792 case EmmcPartitionBoot1:
793 case EmmcPartitionBoot2:
794 Capacity = ExtCsd->BootSizeMult * SIZE_128KB;
795 break;
796 case EmmcPartitionRPMB:
797 Capacity = ExtCsd->RpmbSizeMult * SIZE_128KB;
798 break;
799 case EmmcPartitionGP1:
800 GpSizeMult = (ExtCsd->GpSizeMult[0] | (ExtCsd->GpSizeMult[1] << 8) | (ExtCsd->GpSizeMult[2] << 16));
801 Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
802 break;
803 case EmmcPartitionGP2:
804 GpSizeMult = (ExtCsd->GpSizeMult[3] | (ExtCsd->GpSizeMult[4] << 8) | (ExtCsd->GpSizeMult[5] << 16));
805 Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
806 break;
807 case EmmcPartitionGP3:
808 GpSizeMult = (ExtCsd->GpSizeMult[6] | (ExtCsd->GpSizeMult[7] << 8) | (ExtCsd->GpSizeMult[8] << 16));
809 Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
810 break;
811 case EmmcPartitionGP4:
812 GpSizeMult = (ExtCsd->GpSizeMult[9] | (ExtCsd->GpSizeMult[10] << 8) | (ExtCsd->GpSizeMult[11] << 16));
813 Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
814 break;
815 default:
816 ASSERT (FALSE);
817 continue;
818 }
819
820 MediaNum = Slot->MediaNum;
821 if (Capacity != 0) {
822 Slot->Media[MediaNum].LastBlock = DivU64x32 (Capacity, Slot->Media[MediaNum].BlockSize) - 1;
823 Slot->PartitionType[MediaNum] = PartitionIndex;
824 Private->TotalBlkIoDevices++;
825 Slot->MediaNum++;
826 }
827 }
828 Private->SlotNum++;
829 }
830 Controller++;
831
832 if (!EFI_ERROR (Status)) {
833 PeiServicesInstallPpi (&Private->BlkIoPpiList);
834 PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);
835 } else {
836 if (Private->Pool->Head != NULL) {
837 EmmcPeimFreeMemPool (Private->Pool);
838 }
839 }
840 }
841
842 return EFI_SUCCESS;
843 }