MdeModulePkg/SdMmcPciHcDxe: add Bayhub support

Add support for Bayhub eMMC controller found on AMD
Stoneyridge Chromebooks.

Test: build/boot various google/kahlee-based devices

Signed-off-by: Matt DeVillier <matt.devillier@gmail.com>
This commit is contained in:
Matt DeVillier
2020-01-06 16:15:51 -06:00
committed by Tim Crawford
parent e167ed1a3d
commit 587653cd8b
6 changed files with 708 additions and 15 deletions

View File

@@ -521,15 +521,34 @@ EmmcTuningClkForHs200 (
if (EFI_ERROR (Status)) {
return Status;
}
if(BhtHostPciSupport(PciIo)) {
//set data transfer with 4bit
Status = SdMmcHcSetBusWidth (PciIo, Slot, 4);
//enable hardware tuning
HostCtrl2 = (UINT8)(~0x10);
Status = SdMmcHcAndMmio (PciIo, Slot, 0x110,sizeof (HostCtrl2), &HostCtrl2);
Status = EmmcSendTuningBlk (PassThru, Slot, 4);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "EmmcTuningClkForHs200: Send tuning block fails with %r\n", Status));
return Status;
}
}
//
// Ask the device to send a sequence of tuning blocks till the tuning procedure is done.
//
Retry = 0;
do {
Status = EmmcSendTuningBlk (PassThru, Slot, BusWidth);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "EmmcTuningClkForHs200: Send tuning block fails with %r\n", Status));
return Status;
if(!BhtHostPciSupport(PciIo)) {
Status = EmmcSendTuningBlk (PassThru, Slot, BusWidth);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "EmmcTuningClkForHs200: Send tuning block fails with %r\n", Status));
return Status;
}
} else {
gBS->Stall(5000);
}
Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);
@@ -542,6 +561,10 @@ EmmcTuningClkForHs200 (
}
if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {
if(BhtHostPciSupport(PciIo)) {
//set data transfer with default
Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth);
}
return EFI_SUCCESS;
}
} while (++Retry < 40);
@@ -874,9 +897,53 @@ EmmcSwitchToHS200 (
return Status;
}
Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);
if (EFI_ERROR (Status)) {
return Status;
if (BhtHostPciSupport(PciIo)){
BusMode->BusTiming = SdMmcMmcHs200;
Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength,
BusMode->BusTiming, BusMode->ClockFreq);
if (EFI_ERROR (Status)) {
return Status;
}
Status = SdMmcHcWaitMmioSet (
PciIo,
Slot,
0x1cc,
sizeof (Rca),
BIT14,
BIT14,
SD_MMC_HC_GENERIC_TIMEOUT
);
if (EFI_ERROR (Status)) {
return Status;
}
//Wait 2nd Card Detect debounce Finished by wait twice of debounce max time
UINT32 value32;
while (1) {
Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof(value32), &value32);
if (((value32 >> 18) & 0x01) == ((value32 >> 16) & 0x01)) {
break;
}
}
Status = SdMmcHcWaitMmioSet (
PciIo,
Slot,
0x1cc,
sizeof (Rca),
BIT11,
BIT11,
SD_MMC_CLOCK_STABLE_TIMEOUT
);
if (EFI_ERROR(Status)) {
return Status;
}
} else {
Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);
if (EFI_ERROR (Status)) {
return Status;
}
}
Status = EmmcTuningClkForHs200 (PciIo, PassThru, Slot, BusMode->BusWidth);
@@ -1263,10 +1330,89 @@ EmmcSetBusMode (
DEBUG ((DEBUG_INFO, "EmmcSetBusMode: Target bus mode: timing = %d, width = %d, clock freq = %d, driver strength = %d\n",
BusMode.BusTiming, BusMode.BusWidth, BusMode.ClockFreq, BusMode.DriverStrength.Emmc));
if (BhtHostPciSupport(PciIo)) {
UINT8 EmmcVar;
UINTN EmmcVarSize;
Status = gRT->GetVariable (
L"EMMC_FORCE_CARD_MODE",
&gEfiGenericVariableGuid,
NULL,
&EmmcVarSize,
&EmmcVar
);
if (!EFI_ERROR(Status) && EmmcVar <= 2) {
if (EmmcVar == 2) {
BusMode.BusTiming = SdMmcMmcHs200;
BusMode.ClockFreq = 200;
} else if (EmmcVar == 1) {
BusMode.BusTiming = SdMmcMmcHs200;
BusMode.ClockFreq = 100;
} else {
BusMode.BusTiming = SdMmcMmcHsSdr;
BusMode.ClockFreq = 52;
}
} else {
BusMode.BusTiming = SdMmcMmcHsSdr;
BusMode.ClockFreq = 52;
}
}
if (BusMode.BusTiming == SdMmcMmcHs400) {
//
// Execute HS400 timing switch procedure
//
Status = EmmcSwitchToHS400 (PciIo, PassThru, Slot, Rca, &BusMode);
} else if (BusMode.BusTiming == SdMmcMmcHs200) {
//
// Execute HS200 timing switch procedure
//
Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, &BusMode);
if (EFI_ERROR(Status)) {
if (BhtHostPciSupport(PciIo)) {
UINT32 val32;
UINT16 EmmcVar;
UINTN EmmcVarSize;
#if !defined(HS100_ALLPASS_PHASE) || HS100_ALLPASS_PHASE > 10 || HS100_ALLPASS_PHASE < 0
#error "HS100_ALLPASS_PHASE is undefined or value is invalid"
#else
val32 = PciBhtRead32(PciIo, 0x300);
val32 &= 0xFF0FFFFF;
EmmcVarSize = sizeof(EmmcVar);
Status = gRT->GetVariable (
L"EMMC_HS100_ALLPASS_PHASE",
&gEfiGenericVariableGuid,
NULL,
&EmmcVarSize,
&EmmcVar
);
if (EFI_ERROR(Status) || EmmcVar > 10)
EmmcVar = HS100_ALLPASS_PHASE;
val32 |= (EmmcVar << 20);
PciBhtWrite32(PciIo, 0x300, 0x21000033 | val32);
#endif
BusMode.ClockFreq = 100;
SdMmcHcRwMmio (PciIo, Slot, 0x3C, TRUE, sizeof(val32), &val32);
val32 &= ~BIT22;
SdMmcHcRwMmio (PciIo, Slot, 0x3C, FALSE, sizeof(val32), &val32);
val32 = (BIT26 | BIT25);
SdMmcHcOrMmio (PciIo, Slot, 0x2C, sizeof(val32), &val32);
Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, &BusMode);
if (EFI_ERROR(Status)) {
if (((ExtCsd.DeviceType & BIT1) != 0) && (Private->Capability[Slot].HighSpeed != 0)) {
BusMode.BusTiming = SdMmcMmcHsSdr;
BusMode.ClockFreq = 52;
Status = EmmcSwitchToHighSpeed (PciIo, PassThru, Slot, Rca, &BusMode);
} else if (((ExtCsd.DeviceType & BIT0) != 0) && (Private->Capability[Slot].HighSpeed != 0)) {
BusMode.BusTiming = SdMmcMmcHsSdr;
BusMode.ClockFreq = 26;
Status = EmmcSwitchToHighSpeed (PciIo, PassThru, Slot, Rca, &BusMode);
}
}
}
}
} else {
//
// Note that EmmcSwitchToHighSpeed is also called for SdMmcMmcLegacy