/** Discover all partitions in the EMMC device. @param[in] Device The pointer to the EMMC_DEVICE data structure. @retval EFI_SUCCESS All the partitions in the device are successfully enumerated. @return Others Some error occurs when enumerating the partitions. **/ EFI_STATUS DiscoverAllPartitions ( IN EMMC_DEVICE *Device ) { EFI_STATUS Status; EMMC_PARTITION *Partition; EMMC_CSD *Csd; EMMC_CID *Cid; EMMC_EXT_CSD *ExtCsd; UINT8 Slot; UINT64 Capacity; UINT32 DevStatus; UINT8 Index; UINT32 SecCount; UINT32 GpSizeMult; Slot = Device->Slot; Status = EmmcSendStatus (Device, Slot + 1, &DevStatus); if (EFI_ERROR (Status)) { return Status; } // // Deselect the device to force it enter stby mode before getting CSD // register content. // Note here we don't judge return status as some EMMC devices return // error but the state has been stby. // EmmcSelect (Device, 0); Status = EmmcSendStatus (Device, Slot + 1, &DevStatus); if (EFI_ERROR (Status)) { return Status; } Csd = &Device->Csd; Status = EmmcGetCsd (Device, Slot + 1, Csd); if (EFI_ERROR (Status)) { return Status; } DumpCsd (Csd); if ((Csd->CSizeLow | Csd->CSizeHigh << 2) == 0xFFF) { Device->SectorAddressing = TRUE; } else { Device->SectorAddressing = FALSE; } Cid = &Device->Cid; Status = EmmcGetCid (Device, Slot + 1, Cid); if (EFI_ERROR (Status)) { return Status; } Status = EmmcSelect (Device, Slot + 1); if (EFI_ERROR (Status)) { return Status; } ExtCsd = &Device->ExtCsd; Status = EmmcGetExtCsd (Device, ExtCsd); if (EFI_ERROR (Status)) { return Status; } DumpExtCsd (ExtCsd); if (ExtCsd->ExtCsdRev < 5) { DEBUG ((EFI_D_ERROR, "The EMMC device version is too low, we don't support!!!\n")); return EFI_UNSUPPORTED; } if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) { DEBUG ((EFI_D_ERROR, "The EMMC device doesn't support Partition Feature!!!\n")); return EFI_UNSUPPORTED; } for (Index = 0; Index < EMMC_MAX_PARTITIONS; Index++) { Partition = &Device->Partition[Index]; CopyMem (Partition, &mEmmcPartitionTemplate, sizeof (EMMC_PARTITION)); Partition->Device = Device; InitializeListHead (&Partition->Queue); Partition->BlockIo.Media = &Partition->BlockMedia; Partition->BlockIo2.Media = &Partition->BlockMedia; Partition->PartitionType = Index; Partition->BlockMedia.IoAlign = Device->Private->PassThru->IoAlign; Partition->BlockMedia.BlockSize = 0x200; Partition->BlockMedia.LastBlock = 0x00; Partition->BlockMedia.RemovableMedia = FALSE; Partition->BlockMedia.MediaPresent = TRUE; Partition->BlockMedia.LogicalPartition = FALSE; switch (Index) { case EmmcPartitionUserData: SecCount = *(UINT32*)&ExtCsd->SecCount; Capacity = MultU64x32 ((UINT64) SecCount, 0x200); break; case EmmcPartitionBoot1: case EmmcPartitionBoot2: Capacity = ExtCsd->BootSizeMult * SIZE_128KB; break; case EmmcPartitionRPMB: Capacity = ExtCsd->RpmbSizeMult * SIZE_128KB; break; case EmmcPartitionGP1: GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[0] | (ExtCsd->GpSizeMult[1] << 8) | (ExtCsd->GpSizeMult[2] << 16)); Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB); break; case EmmcPartitionGP2: GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[3] | (ExtCsd->GpSizeMult[4] << 8) | (ExtCsd->GpSizeMult[5] << 16)); Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB); break; case EmmcPartitionGP3: GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[6] | (ExtCsd->GpSizeMult[7] << 8) | (ExtCsd->GpSizeMult[8] << 16)); Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB); break; case EmmcPartitionGP4: GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[9] | (ExtCsd->GpSizeMult[10] << 8) | (ExtCsd->GpSizeMult[11] << 16)); Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB); break; default: ASSERT (FALSE); return EFI_INVALID_PARAMETER; } if (Capacity != 0) { Partition->Enable = TRUE; Partition->BlockMedia.LastBlock = DivU64x32 (Capacity, Partition->BlockMedia.BlockSize) - 1; } if ((ExtCsd->EraseGroupDef & BIT0) == 0) { if (Csd->WriteBlLen < 9) { Partition->EraseBlock.EraseLengthGranularity = 1; } else { Partition->EraseBlock.EraseLengthGranularity = (Csd->EraseGrpMult + 1) * (Csd->EraseGrpSize + 1) * (1 << (Csd->WriteBlLen - 9)); } } else { Partition->EraseBlock.EraseLengthGranularity = 1024 * ExtCsd->HcEraseGrpSize; } } return EFI_SUCCESS; }
/** Discover user area partition in the SD device. @param[in] Device The pointer to the SD_DEVICE data structure. @retval EFI_SUCCESS The user area partition in the SD device is successfully identified. @return Others Some error occurs when identifying the user area. **/ EFI_STATUS DiscoverUserArea ( IN SD_DEVICE *Device ) { EFI_STATUS Status; SD_CSD *Csd; SD_CSD2 *Csd2; SD_CID *Cid; UINT64 Capacity; UINT32 DevStatus; UINT16 Rca; UINT32 CSize; UINT32 CSizeMul; UINT32 ReadBlLen; // // Deselect the device to force it enter stby mode. // Note here we don't judge return status as some SD devices return // error but the state has been stby. // SdSelect (Device, 0); Status = SdSetRca (Device, &Rca); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "DiscoverUserArea(): Assign new Rca = 0x%x fails with %r\n", Rca, Status)); return Status; } Csd = &Device->Csd; Status = SdGetCsd (Device, Rca, Csd); if (EFI_ERROR (Status)) { return Status; } DumpCsd (Csd); Cid = &Device->Cid; Status = SdGetCid (Device, Rca, Cid); if (EFI_ERROR (Status)) { return Status; } GetSdModelName (Device, Cid); Status = SdSelect (Device, Rca); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "DiscoverUserArea(): Reselect the device 0x%x fails with %r\n", Rca, Status)); return Status; } Status = SdSendStatus (Device, Rca, &DevStatus); if (EFI_ERROR (Status)) { return Status; } if (Csd->CsdStructure == 0) { Device->SectorAddressing = FALSE; CSize = (Csd->CSizeHigh << 2 | Csd->CSizeLow) + 1; CSizeMul = (1 << (Csd->CSizeMul + 2)); ReadBlLen = (1 << (Csd->ReadBlLen)); Capacity = MultU64x32 (MultU64x32 ((UINT64)CSize, CSizeMul), ReadBlLen); } else { Device->SectorAddressing = TRUE; Csd2 = (SD_CSD2*)(VOID*)Csd; CSize = (Csd2->CSizeHigh << 16 | Csd2->CSizeLow) + 1; Capacity = MultU64x32 ((UINT64)CSize, SIZE_512KB); } Device->BlockIo.Media = &Device->BlockMedia; Device->BlockIo2.Media = &Device->BlockMedia; Device->BlockMedia.IoAlign = Device->Private->PassThru->IoAlign; Device->BlockMedia.BlockSize = 0x200; Device->BlockMedia.LastBlock = 0x00; Device->BlockMedia.RemovableMedia = TRUE; Device->BlockMedia.MediaPresent = TRUE; Device->BlockMedia.LogicalPartition = FALSE; Device->BlockMedia.LastBlock = DivU64x32 (Capacity, Device->BlockMedia.BlockSize) - 1; if (Csd->EraseBlkEn) { Device->EraseBlock.EraseLengthGranularity = 1; } else { Device->EraseBlock.EraseLengthGranularity = (Csd->SectorSize + 1) * (1 << (Csd->WriteBlLen - 9)); } return Status; }