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