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