]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c
MdeModulePkg/SdMmc: Add EDKII SD/MMC stack
[mirror_edk2.git] / MdeModulePkg / Bus / Sd / SdBlockIoPei / SdBlockIoPei.c
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 "SdBlockIoPei.h"
15
16 //
17 // Template for SD HC Slot Data.
18 //
19 SD_PEIM_HC_SLOT gSdHcSlotTemplate = {
20 SD_PEIM_SLOT_SIG, // Signature
21 { // Media
22 MSG_SD_DP,
23 FALSE,
24 TRUE,
25 FALSE,
26 0x200,
27 0
28 },
29 0, // SdHcBase
30 { // Capability
31 0,
32 },
33 { // Csd
34 0,
35 },
36 TRUE, // SectorAddressing
37 NULL // Private
38 };
39
40 //
41 // Template for SD HC Private Data.
42 //
43 SD_PEIM_HC_PRIVATE_DATA gSdHcPrivateTemplate = {
44 SD_PEIM_SIG, // Signature
45 NULL, // Pool
46 { // BlkIoPpi
47 SdBlockIoPeimGetDeviceNo,
48 SdBlockIoPeimGetMediaInfo,
49 SdBlockIoPeimReadBlocks
50 },
51 { // BlkIo2Ppi
52 EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,
53 SdBlockIoPeimGetDeviceNo2,
54 SdBlockIoPeimGetMediaInfo2,
55 SdBlockIoPeimReadBlocks2
56 },
57 { // BlkIoPpiList
58 EFI_PEI_PPI_DESCRIPTOR_PPI,
59 &gEfiPeiVirtualBlockIoPpiGuid,
60 NULL
61 },
62 { // BlkIo2PpiList
63 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
64 &gEfiPeiVirtualBlockIo2PpiGuid,
65 NULL
66 },
67 { // Slot
68 {
69 0,
70 },
71 {
72 0,
73 },
74 {
75 0,
76 },
77 {
78 0,
79 },
80 {
81 0,
82 },
83 {
84 0,
85 }
86 },
87 0, // SlotNum
88 0 // TotalBlkIoDevices
89 };
90 /**
91 Gets the count of block I/O devices that one specific block driver detects.
92
93 This function is used for getting the count of block I/O devices that one
94 specific block driver detects. To the PEI ATAPI driver, it returns the number
95 of all the detected ATAPI devices it detects during the enumeration process.
96 To the PEI legacy floppy driver, it returns the number of all the legacy
97 devices it finds during its enumeration process. If no device is detected,
98 then the function will return zero.
99
100 @param[in] PeiServices General-purpose services that are available
101 to every PEIM.
102 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
103 instance.
104 @param[out] NumberBlockDevices The number of block I/O devices discovered.
105
106 @retval EFI_SUCCESS The operation performed successfully.
107
108 **/
109 EFI_STATUS
110 EFIAPI
111 SdBlockIoPeimGetDeviceNo (
112 IN EFI_PEI_SERVICES **PeiServices,
113 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
114 OUT UINTN *NumberBlockDevices
115 )
116 {
117 SD_PEIM_HC_PRIVATE_DATA *Private;
118
119 Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
120 *NumberBlockDevices = Private->TotalBlkIoDevices;
121 return EFI_SUCCESS;
122 }
123
124 /**
125 Gets a block device's media information.
126
127 This function will provide the caller with the specified block device's media
128 information. If the media changes, calling this function will update the media
129 information accordingly.
130
131 @param[in] PeiServices General-purpose services that are available to every
132 PEIM
133 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
134 @param[in] DeviceIndex Specifies the block device to which the function wants
135 to talk. Because the driver that implements Block I/O
136 PPIs will manage multiple block devices, the PPIs that
137 want to talk to a single device must specify the
138 device index that was assigned during the enumeration
139 process. This index is a number from one to
140 NumberBlockDevices.
141 @param[out] MediaInfo The media information of the specified block media.
142 The caller is responsible for the ownership of this
143 data structure.
144
145 @par Note:
146 The MediaInfo structure describes an enumeration of possible block device
147 types. This enumeration exists because no device paths are actually passed
148 across interfaces that describe the type or class of hardware that is publishing
149 the block I/O interface. This enumeration will allow for policy decisions
150 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
151 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
152 by a given device type, they should be reported in ascending order; this
153 order also applies to nested partitions, such as legacy MBR, where the
154 outermost partitions would have precedence in the reporting order. The
155 same logic applies to systems such as IDE that have precedence relationships
156 like "Master/Slave" or "Primary/Secondary". The master device should be
157 reported first, the slave second.
158
159 @retval EFI_SUCCESS Media information about the specified block device
160 was obtained successfully.
161 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
162 error.
163
164 **/
165 EFI_STATUS
166 EFIAPI
167 SdBlockIoPeimGetMediaInfo (
168 IN EFI_PEI_SERVICES **PeiServices,
169 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
170 IN UINTN DeviceIndex,
171 OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
172 )
173 {
174 SD_PEIM_HC_PRIVATE_DATA *Private;
175
176 Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
177
178 if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {
179 return EFI_INVALID_PARAMETER;
180 }
181
182 MediaInfo->DeviceType = SD;
183 MediaInfo->MediaPresent = TRUE;
184 MediaInfo->LastBlock = (UINTN)Private->Slot[DeviceIndex - 1].Media.LastBlock;
185 MediaInfo->BlockSize = Private->Slot[DeviceIndex - 1].Media.BlockSize;
186
187 return EFI_SUCCESS;
188 }
189
190 /**
191 Reads the requested number of blocks from the specified block device.
192
193 The function reads the requested number of blocks from the device. All the
194 blocks are read, or an error is returned. If there is no media in the device,
195 the function returns EFI_NO_MEDIA.
196
197 @param[in] PeiServices General-purpose services that are available to
198 every PEIM.
199 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
200 @param[in] DeviceIndex Specifies the block device to which the function wants
201 to talk. Because the driver that implements Block I/O
202 PPIs will manage multiple block devices, PPIs that
203 want to talk to a single device must specify the device
204 index that was assigned during the enumeration process.
205 This index is a number from one to NumberBlockDevices.
206 @param[in] StartLBA The starting logical block address (LBA) to read from
207 on the device
208 @param[in] BufferSize The size of the Buffer in bytes. This number must be
209 a multiple of the intrinsic block size of the device.
210 @param[out] Buffer A pointer to the destination buffer for the data.
211 The caller is responsible for the ownership of the
212 buffer.
213
214 @retval EFI_SUCCESS The data was read correctly from the device.
215 @retval EFI_DEVICE_ERROR The device reported an error while attempting
216 to perform the read operation.
217 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
218 valid, or the buffer is not properly aligned.
219 @retval EFI_NO_MEDIA There is no media in the device.
220 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
221 the intrinsic block size of the device.
222
223 **/
224 EFI_STATUS
225 EFIAPI
226 SdBlockIoPeimReadBlocks (
227 IN EFI_PEI_SERVICES **PeiServices,
228 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
229 IN UINTN DeviceIndex,
230 IN EFI_PEI_LBA StartLBA,
231 IN UINTN BufferSize,
232 OUT VOID *Buffer
233 )
234 {
235 EFI_STATUS Status;
236 UINT32 BlockSize;
237 UINTN NumberOfBlocks;
238 SD_PEIM_HC_PRIVATE_DATA *Private;
239 UINTN Remaining;
240 UINT32 MaxBlock;
241
242 Status = EFI_SUCCESS;
243 Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
244
245 //
246 // Check parameters
247 //
248 if (Buffer == NULL) {
249 return EFI_INVALID_PARAMETER;
250 }
251
252 if (BufferSize == 0) {
253 return EFI_SUCCESS;
254 }
255
256 if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {
257 return EFI_INVALID_PARAMETER;
258 }
259
260 BlockSize = Private->Slot[DeviceIndex - 1].Media.BlockSize;
261 if (BufferSize % BlockSize != 0) {
262 return EFI_BAD_BUFFER_SIZE;
263 }
264
265 if (StartLBA > Private->Slot[DeviceIndex - 1].Media.LastBlock) {
266 return EFI_INVALID_PARAMETER;
267 }
268
269 NumberOfBlocks = BufferSize / BlockSize;
270
271 //
272 // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
273 //
274 Remaining = NumberOfBlocks;
275 MaxBlock = 0xFFFF;
276
277 while (Remaining > 0) {
278 if (Remaining <= MaxBlock) {
279 NumberOfBlocks = Remaining;
280 } else {
281 NumberOfBlocks = MaxBlock;
282 }
283
284 BufferSize = NumberOfBlocks * BlockSize;
285 if (NumberOfBlocks != 1) {
286 Status = SdPeimRwMultiBlocks (&Private->Slot[DeviceIndex - 1], StartLBA, BlockSize, Buffer, BufferSize, TRUE);
287 } else {
288 Status = SdPeimRwSingleBlock (&Private->Slot[DeviceIndex - 1], StartLBA, BlockSize, Buffer, BufferSize, TRUE);
289 }
290 if (EFI_ERROR (Status)) {
291 return Status;
292 }
293
294 StartLBA += NumberOfBlocks;
295 Buffer = (UINT8*)Buffer + BufferSize;
296 Remaining -= NumberOfBlocks;
297 }
298 return Status;
299 }
300
301 /**
302 Gets the count of block I/O devices that one specific block driver detects.
303
304 This function is used for getting the count of block I/O devices that one
305 specific block driver detects. To the PEI ATAPI driver, it returns the number
306 of all the detected ATAPI devices it detects during the enumeration process.
307 To the PEI legacy floppy driver, it returns the number of all the legacy
308 devices it finds during its enumeration process. If no device is detected,
309 then the function will return zero.
310
311 @param[in] PeiServices General-purpose services that are available
312 to every PEIM.
313 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
314 instance.
315 @param[out] NumberBlockDevices The number of block I/O devices discovered.
316
317 @retval EFI_SUCCESS The operation performed successfully.
318
319 **/
320 EFI_STATUS
321 EFIAPI
322 SdBlockIoPeimGetDeviceNo2 (
323 IN EFI_PEI_SERVICES **PeiServices,
324 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
325 OUT UINTN *NumberBlockDevices
326 )
327 {
328 SD_PEIM_HC_PRIVATE_DATA *Private;
329
330 Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
331 *NumberBlockDevices = Private->TotalBlkIoDevices;
332
333 return EFI_SUCCESS;
334 }
335
336 /**
337 Gets a block device's media information.
338
339 This function will provide the caller with the specified block device's media
340 information. If the media changes, calling this function will update the media
341 information accordingly.
342
343 @param[in] PeiServices General-purpose services that are available to every
344 PEIM
345 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
346 @param[in] DeviceIndex Specifies the block device to which the function wants
347 to talk. Because the driver that implements Block I/O
348 PPIs will manage multiple block devices, the PPIs that
349 want to talk to a single device must specify the
350 device index that was assigned during the enumeration
351 process. This index is a number from one to
352 NumberBlockDevices.
353 @param[out] MediaInfo The media information of the specified block media.
354 The caller is responsible for the ownership of this
355 data structure.
356
357 @par Note:
358 The MediaInfo structure describes an enumeration of possible block device
359 types. This enumeration exists because no device paths are actually passed
360 across interfaces that describe the type or class of hardware that is publishing
361 the block I/O interface. This enumeration will allow for policy decisions
362 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
363 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
364 by a given device type, they should be reported in ascending order; this
365 order also applies to nested partitions, such as legacy MBR, where the
366 outermost partitions would have precedence in the reporting order. The
367 same logic applies to systems such as IDE that have precedence relationships
368 like "Master/Slave" or "Primary/Secondary". The master device should be
369 reported first, the slave second.
370
371 @retval EFI_SUCCESS Media information about the specified block device
372 was obtained successfully.
373 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
374 error.
375
376 **/
377 EFI_STATUS
378 EFIAPI
379 SdBlockIoPeimGetMediaInfo2 (
380 IN EFI_PEI_SERVICES **PeiServices,
381 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
382 IN UINTN DeviceIndex,
383 OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
384 )
385 {
386 EFI_STATUS Status;
387 SD_PEIM_HC_PRIVATE_DATA *Private;
388 EFI_PEI_BLOCK_IO_MEDIA Media;
389
390 Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
391
392 Status = SdBlockIoPeimGetMediaInfo (
393 PeiServices,
394 &Private->BlkIoPpi,
395 DeviceIndex,
396 &Media
397 );
398 if (EFI_ERROR (Status)) {
399 return Status;
400 }
401
402 CopyMem (MediaInfo, &(Private->Slot[DeviceIndex - 1].Media), sizeof (EFI_PEI_BLOCK_IO2_MEDIA));
403 return EFI_SUCCESS;
404 }
405
406 /**
407 Reads the requested number of blocks from the specified block device.
408
409 The function reads the requested number of blocks from the device. All the
410 blocks are read, or an error is returned. If there is no media in the device,
411 the function returns EFI_NO_MEDIA.
412
413 @param[in] PeiServices General-purpose services that are available to
414 every PEIM.
415 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
416 @param[in] DeviceIndex Specifies the block device to which the function wants
417 to talk. Because the driver that implements Block I/O
418 PPIs will manage multiple block devices, PPIs that
419 want to talk to a single device must specify the device
420 index that was assigned during the enumeration process.
421 This index is a number from one to NumberBlockDevices.
422 @param[in] StartLBA The starting logical block address (LBA) to read from
423 on the device
424 @param[in] BufferSize The size of the Buffer in bytes. This number must be
425 a multiple of the intrinsic block size of the device.
426 @param[out] Buffer A pointer to the destination buffer for the data.
427 The caller is responsible for the ownership of the
428 buffer.
429
430 @retval EFI_SUCCESS The data was read correctly from the device.
431 @retval EFI_DEVICE_ERROR The device reported an error while attempting
432 to perform the read operation.
433 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
434 valid, or the buffer is not properly aligned.
435 @retval EFI_NO_MEDIA There is no media in the device.
436 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
437 the intrinsic block size of the device.
438
439 **/
440 EFI_STATUS
441 EFIAPI
442 SdBlockIoPeimReadBlocks2 (
443 IN EFI_PEI_SERVICES **PeiServices,
444 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
445 IN UINTN DeviceIndex,
446 IN EFI_PEI_LBA StartLBA,
447 IN UINTN BufferSize,
448 OUT VOID *Buffer
449 )
450 {
451 EFI_STATUS Status;
452 SD_PEIM_HC_PRIVATE_DATA *Private;
453
454 Status = EFI_SUCCESS;
455 Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
456
457 Status = SdBlockIoPeimReadBlocks (
458 PeiServices,
459 &Private->BlkIoPpi,
460 DeviceIndex,
461 StartLBA,
462 BufferSize,
463 Buffer
464 );
465 return Status;
466 }
467
468 /**
469 The user code starts with this function.
470
471 @param FileHandle Handle of the file being invoked.
472 @param PeiServices Describes the list of possible PEI Services.
473
474 @retval EFI_SUCCESS The driver is successfully initialized.
475 @retval Others Can't initialize the driver.
476
477 **/
478 EFI_STATUS
479 EFIAPI
480 InitializeSdBlockIoPeim (
481 IN EFI_PEI_FILE_HANDLE FileHandle,
482 IN CONST EFI_PEI_SERVICES **PeiServices
483 )
484 {
485 EFI_STATUS Status;
486 SD_PEIM_HC_PRIVATE_DATA *Private;
487 EDKII_SD_MMC_HOST_CONTROLLER_PPI *SdMmcHcPpi;
488 UINT32 Index;
489 UINTN *MmioBase;
490 UINT8 BarNum;
491 UINT8 SlotNum;
492 UINT8 Controller;
493 UINT64 Capacity;
494 SD_HC_SLOT_CAP Capability;
495 SD_PEIM_HC_SLOT *Slot;
496 SD_CSD *Csd;
497 SD_CSD2 *Csd2;
498 UINT32 CSize;
499 UINT32 CSizeMul;
500 UINT32 ReadBlLen;
501
502 //
503 // Shadow this PEIM to run from memory
504 //
505 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
506 return EFI_SUCCESS;
507 }
508
509 //
510 // locate Sd host controller PPI
511 //
512 Status = PeiServicesLocatePpi (
513 &gEdkiiPeiSdMmcHostControllerPpiGuid,
514 0,
515 NULL,
516 (VOID **) &SdMmcHcPpi
517 );
518 if (EFI_ERROR (Status)) {
519 return EFI_DEVICE_ERROR;
520 }
521
522 Controller = 0;
523 MmioBase = NULL;
524 while (TRUE) {
525 Status = SdMmcHcPpi->GetSdMmcHcMmioBar (SdMmcHcPpi, Controller, &MmioBase, &BarNum);
526 //
527 // When status is error, meant no controller is found
528 //
529 if (EFI_ERROR (Status)) {
530 break;
531 }
532
533 if (BarNum == 0) {
534 Controller++;
535 continue;
536 }
537
538 Private = AllocateCopyPool (sizeof (SD_PEIM_HC_PRIVATE_DATA), &gSdHcPrivateTemplate);
539 if (Private == NULL) {
540 Status = EFI_OUT_OF_RESOURCES;
541 break;
542 }
543 Private->BlkIoPpiList.Ppi = (VOID*)&Private->BlkIoPpi;
544 Private->BlkIo2PpiList.Ppi = (VOID*)&Private->BlkIo2Ppi;
545 //
546 // Initialize the memory pool which will be used in all transactions.
547 //
548 Status = SdPeimInitMemPool (Private);
549 if (EFI_ERROR (Status)) {
550 Status = EFI_OUT_OF_RESOURCES;
551 break;
552 }
553
554 for (Index = 0; Index < BarNum; Index++) {
555 Status = SdPeimHcGetCapability (MmioBase[Index], &Capability);
556 if (EFI_ERROR (Status)) {
557 continue;
558 }
559 if (Capability.SlotType != 0x1) {
560 DEBUG ((EFI_D_INFO, "The slot at 0x%x is not embedded slot type\n", MmioBase[Index]));
561 Status = EFI_UNSUPPORTED;
562 continue;
563 }
564
565 Status = SdPeimHcReset (MmioBase[Index]);
566 if (EFI_ERROR (Status)) {
567 continue;
568 }
569 Status = SdPeimHcCardDetect (MmioBase[Index]);
570 if (EFI_ERROR (Status)) {
571 continue;
572 }
573 Status = SdPeimHcInitHost (MmioBase[Index]);
574 if (EFI_ERROR (Status)) {
575 continue;
576 }
577
578 SlotNum = Private->SlotNum;
579 Slot = &Private->Slot[SlotNum];
580 CopyMem (Slot, &gSdHcSlotTemplate, sizeof (SD_PEIM_HC_SLOT));
581 Slot->Private = Private;
582 Slot->SdHcBase = MmioBase[Index];
583 CopyMem (&Slot->Capability, &Capability, sizeof (Capability));
584
585 Status = SdPeimIdentification (Slot);
586 if (EFI_ERROR (Status)) {
587 continue;
588 }
589
590 Csd = &Slot->Csd;
591 if (Csd->CsdStructure == 0) {
592 Slot->SectorAddressing = FALSE;
593 CSize = (Csd->CSizeHigh << 2 | Csd->CSizeLow) + 1;
594 CSizeMul = (1 << (Csd->CSizeMul + 2));
595 ReadBlLen = (1 << (Csd->ReadBlLen));
596 Capacity = MultU64x32 (MultU64x32 ((UINT64)CSize, CSizeMul), ReadBlLen);
597 } else {
598 Slot->SectorAddressing = TRUE;
599 Csd2 = (SD_CSD2*)(VOID*)Csd;
600 CSize = (Csd2->CSizeHigh << 16 | Csd2->CSizeLow) + 1;
601 Capacity = MultU64x32 ((UINT64)CSize, SIZE_512KB);
602 }
603
604 Slot->Media.LastBlock = DivU64x32 (Capacity, Slot->Media.BlockSize) - 1;
605
606 Private->TotalBlkIoDevices++;
607 Private->SlotNum++;
608 }
609
610 Controller++;
611 if (!EFI_ERROR (Status)) {
612 PeiServicesInstallPpi (&Private->BlkIoPpiList);
613 }
614 }
615
616 return EFI_SUCCESS;
617 }