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