From f15ac4583b70dc2995f43ce65ae178c225572a61 Mon Sep 17 00:00:00 2001 From: Matt DeVillier Date: Mon, 6 Jan 2020 16:15:51 -0600 Subject: [PATCH] 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 --- .../Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c | 210 +++++++- .../Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c | 60 +++ .../Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h | 9 + .../Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf | 7 +- .../Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c | 481 +++++++++++++++++- .../Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h | 38 ++ 6 files changed, 782 insertions(+), 23 deletions(-) mode change 100755 => 100644 MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c old mode 100755 new mode 100644 index ca30e44221..1849df45b0 --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c @@ -526,15 +526,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); @@ -547,6 +566,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); @@ -770,10 +793,21 @@ EmmcSwitchToHighSpeed ( Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru); + DbgMsg("switch to HS mode %dMHz\n", ClockFreq); + Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, IsDdr, BusWidth); if (EFI_ERROR (Status)) { return Status; } + + if (BhtHostPciSupport(PciIo)) { + HsTiming = 1; + Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, Timing, ClockFreq); + if (EFI_ERROR (Status)) { + return Status; + } + } + // // Set to Hight Speed timing // @@ -796,8 +830,10 @@ EmmcSwitchToHighSpeed ( return Status; } - HsTiming = 1; - Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, Timing, ClockFreq); + if (!BhtHostPciSupport(PciIo)) { + HsTiming = 1; + Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, Timing, ClockFreq); + } return Status; } @@ -837,6 +873,8 @@ EmmcSwitchToHS200 ( Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru); + DbgMsg("switch to HS200 mode %dMHz\n", ClockFreq); + if ((BusWidth != 4) && (BusWidth != 8)) { return EFI_INVALID_PARAMETER; } @@ -845,6 +883,15 @@ EmmcSwitchToHS200 ( if (EFI_ERROR (Status)) { return Status; } + + if (BhtHostPciSupport(PciIo)){ + HsTiming = 2; + Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, Timing, ClockFreq); + if (EFI_ERROR (Status)) { + return Status; + } + } + // // Set to HS200/SDR104 timing // @@ -866,31 +913,73 @@ EmmcSwitchToHS200 ( // // Wait Internal Clock Stable in the Clock Control register to be 1 before set SD Clock Enable bit // - Status = SdMmcHcWaitMmioSet ( - PciIo, - Slot, - SD_MMC_HC_CLOCK_CTRL, - sizeof (ClockCtrl), - BIT1, - BIT1, - SD_MMC_HC_GENERIC_TIMEOUT + if (BhtHostPciSupport(PciIo)) { + Status = SdMmcHcWaitMmioSet ( + PciIo, + Slot, + 0x1cc, + sizeof (ClockCtrl), + BIT14, + BIT14, + SD_MMC_HC_GENERIC_TIMEOUT ); + } else { + Status = SdMmcHcWaitMmioSet ( + PciIo, + Slot, + SD_MMC_HC_CLOCK_CTRL, + sizeof (ClockCtrl), + BIT1, + BIT1, + SD_MMC_HC_GENERIC_TIMEOUT + ); + } if (EFI_ERROR (Status)) { return Status; } + + if (BhtHostPciSupport(PciIo)) { + //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; + } + } + } // // Set SD Clock Enable in the Clock Control register to 1 // ClockCtrl = BIT2; Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl); - HsTiming = 2; - Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, Timing, ClockFreq); - if (EFI_ERROR (Status)) { - return Status; + if (!BhtHostPciSupport(PciIo)) { + HsTiming = 2; + Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, Timing, ClockFreq); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + Status = SdMmcHcWaitMmioSet ( + PciIo, + Slot, + 0x1cc, + sizeof (ClockCtrl), + BIT11, + BIT11, + SD_MMC_CLOCK_STABLE_TIMEOUT + ); + if (EFI_ERROR(Status)) { + DbgMsg("Wait Clock Stable timeout, ClockFreq=%d\n", ClockFreq); + return Status; + } } Status = EmmcTuningClkForHs200 (PciIo, PassThru, Slot, BusWidth); + if (EFI_ERROR(Status)) { + DbgMsg("Emmc tuning failed\n"); + } return Status; } @@ -1068,6 +1157,37 @@ EmmcSetBusMode ( DEBUG ((DEBUG_INFO, "EmmcSetBusMode: HsTiming %d ClockFreq %d BusWidth %d Ddr %a\n", HsTiming, ClockFreq, BusWidth, IsDdr ? "TRUE":"FALSE")); + 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) { + HsTiming = 2; + IsDdr = FALSE; + ClockFreq = 200; + } else if (EmmcVar == 1) { + HsTiming = 2; + IsDdr = FALSE; + ClockFreq = 100; + } else { + HsTiming = 1; + IsDdr = FALSE; + ClockFreq = 52; + } + } else { + HsTiming = 1; + IsDdr = FALSE; + ClockFreq = 52; + } + } + if (HsTiming == 3) { // // Execute HS400 timing switch procedure @@ -1078,6 +1198,60 @@ EmmcSetBusMode ( // Execute HS200 timing switch procedure // Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, ClockFreq, BusWidth); + if (EFI_ERROR(Status)) { + if (BhtHostPciSupport(PciIo)) { + UINT32 val32; + UINT16 EmmcVar; + UINTN EmmcVarSize; + DbgMsg("switch to HS200 200MHZ failed, freq decrease to 100MHz\n"); +#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 + 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, ClockFreq, BusWidth); + if (EFI_ERROR(Status)) { + if (((ExtCsd.DeviceType & BIT1) != 0) && (Private->Capability[Slot].HighSpeed != 0)) { + DbgMsg("switch to HS200 100MHZ failed, mode decrease to HS 50MHz\n"); + + HsTiming = 1; + IsDdr = FALSE; + ClockFreq = 52; + Status = EmmcSwitchToHighSpeed (PciIo, PassThru, Slot, Rca, ClockFreq, IsDdr, BusWidth); + } else if (((ExtCsd.DeviceType & BIT0) != 0) && (Private->Capability[Slot].HighSpeed != 0)) { + DbgMsg("switch to HS200 100MHZ failed, mode decrease to HS 25MHz\n"); + + HsTiming = 1; + IsDdr = FALSE; + ClockFreq = 26; + Status = EmmcSwitchToHighSpeed (PciIo, PassThru, Slot, Rca, ClockFreq, IsDdr, BusWidth); + } else { + DbgMsg("switch to HS200 100MHZ failed, but emmc chip didn't support hs mode\n"); + } + } + } + } } else { // // Execute High Speed timing switch procedure diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c index 008c0589df..388efb818c 100644 --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c @@ -295,6 +295,13 @@ SdMmcPciHcEnumerateDevice ( continue; } + if (BhtHostPciSupport(Private->PciIo)) { + Status = SdMmcHcGetCapability (Private->PciIo, Slot, &Private->Capability[Slot]); + if (EFI_ERROR (Status)) { + continue; + } + } + Private->Slot[Slot].MediaPresent = TRUE; Private->Slot[Slot].Initialized = TRUE; RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE); @@ -311,6 +318,7 @@ SdMmcPciHcEnumerateDevice ( // This card doesn't get initialized correctly. // if (Index == RoutineNum) { + DEBUG ((DEBUG_INFO, "Load driver failure\n")); Private->Slot[Slot].Initialized = FALSE; } @@ -530,6 +538,8 @@ SdMmcPciHcDriverBindingStart ( UINT32 RoutineNum; BOOLEAN MediaPresent; BOOLEAN Support64BitDma; + UINT16 IntStatus; + UINT32 value; DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStart: Start\n")); @@ -685,6 +695,13 @@ SdMmcPciHcDriverBindingStart ( continue; } + if (BhtHostPciSupport(PciIo)) { + Status = SdMmcHcGetCapability (PciIo, Slot, &Private->Capability[Slot]); + if (EFI_ERROR (Status)) { + continue; + } + } + Private->Slot[Slot].MediaPresent = TRUE; Private->Slot[Slot].Initialized = TRUE; RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE); @@ -701,9 +718,52 @@ SdMmcPciHcDriverBindingStart ( // This card doesn't get initialized correctly. // if (Index == RoutineNum) { + DEBUG ((DEBUG_INFO, "Load driver failure\n")); Private->Slot[Slot].Initialized = FALSE; } } + if (BhtHostPciSupport(Private->PciIo)) { + DbgMsg("HOST_CLK_DRIVE_STRENGTH: 0x%x\n",HOST_CLK_DRIVE_STRENGTH); + DbgMsg("HOST_DAT_DRIVE_STRENGTH: 0x%x\n",HOST_DAT_DRIVE_STRENGTH); + DbgMsg("HS200_ALLPASS_PHASE: 0x%x\n",HS200_ALLPASS_PHASE); + DbgMsg("HS100_ALLPASS_PHASE: 0x%x\n",HS100_ALLPASS_PHASE); + + SdMmcHcRwMmio (Private->PciIo,0,0x110,TRUE,sizeof (value),&value); + DbgMsg("0x110: 0x%x\n",value); + + SdMmcHcRwMmio (Private->PciIo,0,0x114,TRUE,sizeof (value),&value); + DbgMsg("0x114: 0x%x\n",value); + + SdMmcHcRwMmio (Private->PciIo,0,0x1a8,TRUE,sizeof (value),&value); + DbgMsg("MEM 1A8: 0x%x\n",value); + SdMmcHcRwMmio (Private->PciIo,0,0x1ac,TRUE,sizeof (value),&value); + DbgMsg("MEM 1AC: 0x%x\n",value); + SdMmcHcRwMmio (Private->PciIo,0,0x1B0,TRUE,sizeof (value),&value); + DbgMsg("MEM 1B0: 0x%x\n",value); + SdMmcHcRwMmio (Private->PciIo,0,0x1CC,TRUE,sizeof (value),&value); + DbgMsg("MEM 1CC: 0x%x\n",value); + + DbgMsg(" - pcr 0x300 = 0x%08x\n", PciBhtRead32(Private->PciIo, 0x300)); + DbgMsg(" - pcr 0x304 = 0x%08x\n", PciBhtRead32(Private->PciIo, 0x304)); + DbgMsg(" - pcr 0x328 = 0x%08x\n", PciBhtRead32(Private->PciIo, 0x328)); + DbgMsg(" - pcr 0x3e4 = 0x%08x\n", PciBhtRead32(Private->PciIo, 0x3e4)); + + SdMmcHcRwMmio (Private->PciIo,0,0x040,TRUE,sizeof (value),&value); + DbgMsg("0x40: 0x%x\n",value); + + SdMmcHcRwMmio (Private->PciIo,0,SD_MMC_HC_PRESENT_STATE,TRUE,sizeof (value),&value); + DbgMsg("Present State: 0x%x\n",value); + SdMmcHcRwMmio (Private->PciIo,0,SD_MMC_HC_HOST_CTRL1,TRUE,sizeof (IntStatus),&IntStatus); + DbgMsg("Power&Host1: 0x%x\n",IntStatus); + SdMmcHcRwMmio (Private->PciIo,0,SD_MMC_HC_CLOCK_CTRL,TRUE,sizeof (IntStatus),&IntStatus); + DbgMsg("CLK: 0x%x\n",IntStatus); + SdMmcHcRwMmio (Private->PciIo,0,SD_MMC_HC_TIMEOUT_CTRL,TRUE,sizeof (IntStatus),&IntStatus); + DbgMsg("SWR&Timeout: 0x%x\n",IntStatus); + SdMmcHcRwMmio (Private->PciIo,0,SD_MMC_HC_NOR_INT_STS,TRUE,sizeof (value),&value); + DbgMsg("INR&IER: 0x%x\n",value); + SdMmcHcRwMmio (Private->PciIo,0,SD_MMC_HC_HOST_CTRL2,TRUE,sizeof (IntStatus),&IntStatus); + DbgMsg("Host2: 0x%x\n",IntStatus); + } // // Enable 64-bit DMA support in the PCI layer if this controller diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h index 8c1a589078..faa0b4e180 100644 --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h @@ -25,6 +25,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include #include #include #include @@ -38,6 +39,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include +#include + #include "SdMmcPciHci.h" extern EFI_COMPONENT_NAME_PROTOCOL gSdMmcPciHcComponentName; @@ -51,10 +54,16 @@ extern EDKII_SD_MMC_OVERRIDE *mOverride; #define SD_MMC_HC_PRIVATE_FROM_THIS(a) \ CR(a, SD_MMC_HC_PRIVATE_DATA, PassThru, SD_MMC_HC_PRIVATE_SIGNATURE) +#define HOST_CLK_DRIVE_STRENGTH 2 +#define HOST_DAT_DRIVE_STRENGTH 2 +#define HS200_ALLPASS_PHASE 0 +#define HS100_ALLPASS_PHASE 6 + // // Generic time out value, 1 microsecond as unit. // #define SD_MMC_HC_GENERIC_TIMEOUT 1 * 1000 * 1000 +#define SD_MMC_CLOCK_STABLE_TIMEOUT 3 * 1000 // // SD/MMC async transfer timer interval, set by experience. diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf index 1246e1d88d..d52e243bdd 100644 --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf @@ -18,12 +18,12 @@ ## [Defines] - INF_VERSION = 0x00010005 + INF_VERSION = 0x00010007 BASE_NAME = SdMmcPciHcDxe MODULE_UNI_FILE = SdMmcPciHcDxe.uni FILE_GUID = 8E325979-3FE1-4927-AAE2-8F5C4BD2AF0D MODULE_TYPE = UEFI_DRIVER - VERSION_STRING = 1.0 + VERSION_STRING = 1.5.4 ENTRY_POINT = InitializeSdMmcPciHcDxe # @@ -67,6 +67,9 @@ gEfiPciIoProtocolGuid ## TO_START gEfiSdMmcPassThruProtocolGuid ## BY_START +[Guids] + gEfiGenericVariableGuid + # [Event] # EVENT_TYPE_PERIODIC_TIMER ## SOMETIMES_CONSUMES diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c index ddf6dcf2c4..420683dc3e 100644 --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c @@ -17,6 +17,9 @@ #include "SdMmcPciHcDxe.h" +int g_deviceId = 0; + + /** Dump the content of SD/MMC host controller's Capability Register. @@ -1031,6 +1034,15 @@ SdMmcHcInitPowerVoltage ( // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register // Status = SdMmcHcPowerControl (PciIo, Slot, MaxVoltage); + if (BhtHostPciSupport(PciIo)){ + // 1.8V signaling enable + HostCtrl2 = BIT3; + Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + gBS->Stall (5000); + if (EFI_ERROR (Status)) { + return Status; + } + } return Status; } @@ -1082,6 +1094,7 @@ SdMmcHcInitHost ( EFI_STATUS Status; EFI_PCI_IO_PROTOCOL *PciIo; SD_MMC_HC_SLOT_CAP Capability; + UINT32 value32; // // Notify the SD/MMC override protocol that we are about to initialize @@ -1104,14 +1117,199 @@ SdMmcHcInitHost ( PciIo = Private->PciIo; Capability = Private->Capability[Slot]; + if (BhtHostPciSupport(PciIo)){ + UINT8 CardMode; + UINT16 EmmcVar; + UINTN EmmcVarSize; + UINT64 Cap; + + DbgMsg("find bht emmc chip\n"); + + //unlock PCR write protect +#ifdef DISABLE_L1_2 + PciBhtAnd32(PciIo, 0xd0, ~(BIT31)); + PciBhtAnd32(PciIo, 0x90, ~(BIT1 | BIT0)); + + value32 = PciBhtRead32(PciIo, 0xe0); + value32 &= ~(BIT31 | BIT30 | BIT29 | BIT28); + value32 |= (BIT29 | BIT28); + PciBhtWrite32(PciIo, 0xe0, value32); + + value32 = PciBhtRead32(PciIo, 0xfc); + value32 &= ~(BIT19 | BIT18 | BIT17 | BIT16); + value32 |= (BIT19); + PciBhtWrite32(PciIo, 0xfc, value32); + + value32 = PciBhtRead32(PciIo, 0x3f4); + value32 &= ~(BIT3 | BIT2 | BIT1 | BIT0); + value32 |= (BIT3 | BIT1); + PciBhtWrite32(PciIo, 0x3f4, value32); + + value32 = PciBhtRead32(PciIo, 0x248); + value32 &= ~(BIT3 | BIT2 | BIT1 | BIT0); + value32 |= (BIT3 | BIT1); + PciBhtWrite32(PciIo, 0x248, value32); + + value32 = PciBhtRead32(PciIo, 0x90); + value32 &= ~(BIT1 | BIT0); + value32 |= (BIT1); + PciBhtWrite32(PciIo, 0x90, value32); +#endif + + /* FET on */ + PciBhtOr32(PciIo, 0xEC, 0x3); + /* Led on */ + //PciBhtAnd32(PciIo, 0x334, (UINT32)~BIT13); + PciBhtOr32(PciIo, 0xD4, BIT6); + /* Set 1.8v emmc signaling flag */ + PciBhtOr32(PciIo, 0x308, BIT4); + /* Set 200MBaseClock */ + value32 = PciBhtRead32(PciIo, 0x304); + value32 &= 0x0000FFFF; + value32 |= 0x25100000; +#if !defined(HOST_CLK_DRIVE_STRENGTH) || HOST_CLK_DRIVE_STRENGTH > 7 || HOST_CLK_DRIVE_STRENGTH < 0 +#error "HOST_CMD_DRIVE_STRENGTH is undefined or value is invalid" +#else + EmmcVarSize = sizeof(EmmcVar); + Status = gRT->GetVariable ( + L"EMMC_CLK_DRIVER_STRENGTH", + &gEfiGenericVariableGuid, + NULL, + &EmmcVarSize, + &EmmcVar + ); + if (EFI_ERROR(Status)) + EmmcVar = HOST_CLK_DRIVE_STRENGTH; + value32 &= 0xFFFFFF8F; + value32 |= ((EmmcVar & 0x7) << 4); +#endif +#if !defined(HOST_DAT_DRIVE_STRENGTH) || HOST_DAT_DRIVE_STRENGTH > 7 || HOST_DAT_DRIVE_STRENGTH < 0 +#error "HOST_DATA_DRIVE_STRENGTH is undefined or value is invalid" +#else + EmmcVarSize = sizeof(EmmcVar); + Status = gRT->GetVariable ( + L"EMMC_DATA_DRIVER_STRENGTH", + &gEfiGenericVariableGuid, + NULL, + &EmmcVarSize, + &EmmcVar + ); + if (EFI_ERROR(Status)) + EmmcVar = HOST_DAT_DRIVE_STRENGTH; + value32 &= 0xFFFFFFF1; + value32 |= ((EmmcVar & 0x7) << 1); +#endif + PciBhtWrite32(PciIo, 0x304, value32); + PciBhtOr32(PciIo, 0x3E4, BIT22); + + EmmcVarSize = sizeof(CardMode); + Status = gRT->GetVariable ( + L"EMMC_FORCE_CARD_MODE", + &gEfiGenericVariableGuid, + NULL, + &EmmcVarSize, + &CardMode + ); + if (EFI_ERROR(Status) || CardMode > 2) { + CardMode = 0; + } + + if (CardMode == 1) { +#if !defined(HS100_ALLPASS_PHASE) || HS100_ALLPASS_PHASE > 10 || HS100_ALLPASS_PHASE < 0 +#error "HS200_ALLPASS_PHASE is undefined or value is invalid" +#else + 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; +#endif + } else if (CardMode == 2) { +#if !defined(HS200_ALLPASS_PHASE) || HS200_ALLPASS_PHASE > 10 || HS200_ALLPASS_PHASE < 0 +#error "HS200_ALLPASS_PHASE is undefined or value is invalid" +#else + EmmcVarSize = sizeof(EmmcVar); + Status = gRT->GetVariable ( + L"EMMC_HS200_ALLPASS_PHASE", + &gEfiGenericVariableGuid, + NULL, + &EmmcVarSize, + &EmmcVar + ); + if (EFI_ERROR(Status) || EmmcVar > 10) + EmmcVar = HS200_ALLPASS_PHASE; + } +#endif + + value32 = 0x21000033 | (EmmcVar << 20); + PciBhtWrite32(PciIo, 0x300, value32); + + //enable internal clk + value32 = BIT0; + Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL,sizeof(value32), &value32); + + //reset pll start + Status = SdMmcHcRwMmio (PciIo, Slot, 0x1CC, TRUE, sizeof(value32), &value32); + value32 |= BIT12; + Status = SdMmcHcRwMmio (PciIo, Slot, 0x1CC, FALSE, sizeof(value32), &value32); + gBS->Stall(1); + + //reset pll end + Status = SdMmcHcRwMmio (PciIo, Slot, 0x1CC, TRUE,sizeof(value32), &value32); + value32 &= ~BIT12; + value32 |= BIT18; + Status = SdMmcHcRwMmio (PciIo, Slot, 0x1CC, FALSE, sizeof(value32), &value32); + + //wait BaseClk stable 0x1CC bit14 + Status = SdMmcHcRwMmio (PciIo, Slot, 0x1CC, TRUE, sizeof(value32), &value32); + while(!(value32&BIT14)){ + gBS->Stall(100); + Status = SdMmcHcRwMmio (PciIo, Slot, 0x1CC, TRUE, sizeof(value32), &value32); + DbgMsg("1CC=0x%08x\n", value32); + } + + if (value32 & BIT18) + { + //Wait 2nd Card Detect debounce Finished by wait twice of debounce max time + while (1) { + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof(value32), &value32); + if (((value32 >> 16) & 0x01) == ((value32 >> 18) & 0x01)) + break; + } + //force pll active end + Status = SdMmcHcRwMmio (PciIo, Slot, 0x1CC, TRUE, sizeof(value32), &value32); + value32 &= ~BIT18; + Status = SdMmcHcRwMmio (PciIo, Slot, 0x1CC, FALSE, sizeof(value32), &value32); + } + + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CAP, TRUE, sizeof (Cap), &Cap); + if (EFI_ERROR (Status)) { + return Status; + } + CopyMem (&Capability, &Cap, sizeof (Cap)); + + Status = SdMmcHcInitPowerVoltage (PciIo, Slot, Capability); + if (EFI_ERROR (Status)) { + DbgMsg("emmc host init failure\n"); + return Status; + } + } + Status = SdMmcHcInitClockFreq (PciIo, Slot, Private->BaseClkFreq[Slot]); if (EFI_ERROR (Status)) { return Status; } - Status = SdMmcHcInitPowerVoltage (PciIo, Slot, Capability); - if (EFI_ERROR (Status)) { - return Status; + if (!BhtHostPciSupport(PciIo)){ + Status = SdMmcHcInitPowerVoltage (PciIo, Slot, Capability); + if (EFI_ERROR (Status)) { + return Status; + } } Status = SdMmcHcInitTimeoutCtrl (PciIo, Slot); @@ -2096,3 +2294,280 @@ SdMmcWaitTrbResult ( return EFI_TIMEOUT; } +BOOLEAN BhtHostPciSupport(EFI_PCI_IO_PROTOCOL *PciIo) +{ + PCI_TYPE00 Pci; + + PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, + 0, sizeof Pci / sizeof (UINT32), &Pci); + + DEBUG ((DEBUG_INFO, "check device %04x:%04x\n", Pci.Hdr.VendorId, Pci.Hdr.DeviceId)); + + if (Pci.Hdr.VendorId != 0x1217) + goto end; + + switch (Pci.Hdr.DeviceId) + { + case 0x8420: //PCI_DEV_ID_SDS0 + case 0x8421: //PCI_DEV_ID_SDS1 + case 0x8520: //PCI_DEV_ID_FJ2 + case 0x8620: //PCI_DEV_ID_SB0 + case 0x8621: //PCI_DEV_ID_SB1 + g_deviceId = Pci.Hdr.DeviceId; + return 1; + default: + break; + } + + end: + return 0; +} + +void DbgNull(IN CONST CHAR16 * fmt, ...) +{ +} + +UINT32 bht_readl(EFI_PCI_IO_PROTOCOL *PciIo, UINT32 offset) +{ + UINT32 arg; + PciIo->Mem.Read(PciIo,EfiPciIoWidthUint32,1,offset,1,&arg); + return arg; +} + +void bht_writel(EFI_PCI_IO_PROTOCOL *PciIo, UINT32 offset, UINT32 value) +{ + PciIo->Mem.Write(PciIo,EfiPciIoWidthUint32,1,offset,1,&value); +} + + +UINT32 PciBhtRead32(EFI_PCI_IO_PROTOCOL *PciIo, UINT32 offset) +{ + UINT32 i = 0; + UINT32 tmp[3] = {0}; + + if((g_deviceId == PCI_DEV_ID_SDS0) || + (g_deviceId == PCI_DEV_ID_SDS1) || + (g_deviceId == PCI_DEV_ID_FJ2) || + (g_deviceId == PCI_DEV_ID_SB0) || + (g_deviceId == PCI_DEV_ID_SB1)) + { + // For Sandstorm, HW implement a mapping method by memory space reg to access PCI reg. + // Enable mapping + + // Check function conflict + if((g_deviceId == PCI_DEV_ID_SDS0) || + (g_deviceId == PCI_DEV_ID_FJ2) || + (g_deviceId == PCI_DEV_ID_SB0) || + (g_deviceId == PCI_DEV_ID_SB1)) + { + i = 0; + bht_writel(PciIo, BHT_PCIRMappingEn, 0x40000000); + while((bht_readl(PciIo, BHT_PCIRMappingEn) & 0x40000000) == 0) + { + if(i == 5) + { + //DbgMsg((DRIVERNAME " - %s() function 0 can't lock!\n", __FUNCTION__)); + goto RD_DIS_MAPPING; + } + gBS->Stall(1000); + i++; + bht_writel(PciIo, BHT_PCIRMappingEn, 0x40000000); + + } + } + else if(g_deviceId == PCI_DEV_ID_SDS1) + { + i = 0; + bht_writel(PciIo, BHT_PCIRMappingEn, 0x20000000); + while((bht_readl(PciIo, BHT_PCIRMappingEn) & 0x20000000) == 0) + { + if(i == 5) + { + //DbgErr((DRIVERNAME " - %s() function 1 can't lock!\n", __FUNCTION__)); + goto RD_DIS_MAPPING; + } + gBS->Stall(1000); + i++; + bht_writel(PciIo, BHT_PCIRMappingEn, 0x20000000); + } + } + + // Check last operation is complete + i = 0; + while(bht_readl(PciIo, BHT_PCIRMappingCtl) & 0xc0000000) + { + if(i == 5) + { + //DbgErr((DRIVERNAME " - [204] = 0x%x\n", RegisterRead32(ELN_dPCIRMappingCtl))); + //DbgErr((DRIVERNAME " - [208] = 0x%x\n", RegisterRead32(ELN_dPCIRMappingEn))); + //DbgErr((DRIVERNAME " - %s() check last operation complete timeout!!!\n", __FUNCTION__)); + goto RD_DIS_MAPPING; + } + gBS->Stall(1000); + i += 1; + } + + // Set register address + tmp[0] |= 0x40000000; + tmp[0] |= offset; + bht_writel(PciIo, BHT_PCIRMappingCtl, tmp[0]); + + // Check read is complete + i = 0; + while(bht_readl(PciIo, BHT_PCIRMappingCtl) & 0x40000000) + { + if(i == 5) + { + //DbgErr((DRIVERNAME " - %s() check read operation complete timeout!!!\n", __FUNCTION__)); + goto RD_DIS_MAPPING; + } + gBS->Stall(1000); + i += 1; + } + + // Get PCIR value + tmp[1] = bht_readl(PciIo, BHT_PCIRMappingVal); + +RD_DIS_MAPPING: + // Disable mapping + bht_writel(PciIo, BHT_PCIRMappingEn, 0x80000000); + + //DbgDebug(L"%s offset=%x Value:%x\n", __FUNCTION__, offset, tmp[1]); + return tmp[1]; + } + + //DbgDebug(L"%s offset=%x Value:%x\n", __FUNCTION__, offset, tmp[0]); + return tmp[0]; +} + +void PciBhtWrite32(EFI_PCI_IO_PROTOCOL *PciIo, UINT32 offset, UINT32 value) +{ + UINT32 tmp = 0; + UINT32 i = 0; + + if((g_deviceId == PCI_DEV_ID_SDS0) || + (g_deviceId == PCI_DEV_ID_SDS1) || + (g_deviceId == PCI_DEV_ID_FJ2) || + (g_deviceId == PCI_DEV_ID_SB0) || + (g_deviceId == PCI_DEV_ID_SB1)) + { + // For Sandstorm, HW implement a mapping method by memory space reg to access PCI reg. + // Upper caller doesn't need to set 0xD0. + + // Enable mapping + + // Check function conflict + if((g_deviceId == PCI_DEV_ID_SDS0) || + (g_deviceId == PCI_DEV_ID_FJ2) || + (g_deviceId == PCI_DEV_ID_SB0) || + (g_deviceId == PCI_DEV_ID_SB1)) + { + i = 0; + bht_writel(PciIo, BHT_PCIRMappingEn, 0x40000000); + while((bht_readl(PciIo, BHT_PCIRMappingEn) & 0x40000000) == 0) + { + if(i == 5) + { + //DbgErr((DRIVERNAME " - %s() function 0 can't lock!\n", __FUNCTION__)); + goto WR_DIS_MAPPING; + } + + gBS->Stall(1000); + i++; + bht_writel(PciIo, BHT_PCIRMappingEn, 0x40000000); + } + } + else if(g_deviceId == PCI_DEV_ID_SDS1) + { + i = 0; + bht_writel(PciIo, BHT_PCIRMappingEn, 0x20000000); + + while((bht_readl(PciIo, BHT_PCIRMappingEn) & 0x20000000) == 0) + { + if(i == 5) + { + //DbgErr((DRIVERNAME " - %s() function 0 can't lock!\n", __FUNCTION__)); + goto WR_DIS_MAPPING; + } + + gBS->Stall(1000); + i++; + bht_writel(PciIo, BHT_PCIRMappingEn, 0x20000000); + } + } + + // Enable MEM access + bht_writel(PciIo, BHT_PCIRMappingVal, 0x80000000); + bht_writel(PciIo, BHT_PCIRMappingCtl, 0x800000D0); + + // Check last operation is complete + i = 0; + while(bht_readl(PciIo, BHT_PCIRMappingCtl) & 0xc0000000) + { + if(i == 5) + { + //DbgErr((DRIVERNAME " - %s() check last operation complete timeout!!!\n", __FUNCTION__)); + goto WR_DIS_MAPPING; + } + gBS->Stall(1000); + i += 1; + } + + // Set write value + bht_writel(PciIo, BHT_PCIRMappingVal, value); + // Set register address + tmp |= 0x80000000; + tmp |= offset; + bht_writel(PciIo, BHT_PCIRMappingCtl, tmp); + + // Check write is complete + i = 0; + while(bht_readl(PciIo, BHT_PCIRMappingCtl) & 0x80000000) + { + if(i == 5) + { + //DbgErr((DRIVERNAME " - %s() check write operation complete timeout!!!\n", __FUNCTION__)); + goto WR_DIS_MAPPING; + } + gBS->Stall(1000); + i += 1; + } + +WR_DIS_MAPPING: + // Disable MEM access + bht_writel(PciIo, BHT_PCIRMappingVal, 0x80000001); + bht_writel(PciIo, BHT_PCIRMappingCtl, 0x800000D0); + + // Check last operation is complete + i = 0; + while(bht_readl(PciIo, BHT_PCIRMappingCtl) & 0xc0000000) + { + if(i == 5) + { + //DbgErr((DRIVERNAME " - %s() check last operation complete timeout!!!\n", __FUNCTION__)); + break; + } + gBS->Stall(1000); + i += 1; + } + + // Disable function conflict + + // Disable mapping + bht_writel(PciIo, BHT_PCIRMappingEn, 0x80000000); + } +} + +void PciBhtOr32(EFI_PCI_IO_PROTOCOL *PciIo, UINT32 offset, UINT32 value) +{ + UINT32 arg; + arg = PciBhtRead32(PciIo, offset); + PciBhtWrite32(PciIo, offset, value | arg); +} + +void PciBhtAnd32(EFI_PCI_IO_PROTOCOL *PciIo, UINT32 offset, UINT32 value) +{ + UINT32 arg; + arg = PciBhtRead32(PciIo, offset); + PciBhtWrite32(PciIo, offset, value & arg); +} diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h index dd45cbde5b..f2b0162e56 100644 --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h @@ -552,4 +552,42 @@ SdMmcHcUhsSignaling ( IN SD_MMC_BUS_MODE Timing ); + + +BOOLEAN +BhtHostPciSupport(EFI_PCI_IO_PROTOCOL *PciIo); +UINT32 +PciBhtRead32(EFI_PCI_IO_PROTOCOL *PciIo, UINT32 offset); +void +PciBhtWrite32(EFI_PCI_IO_PROTOCOL *PciIo, UINT32 offset, UINT32 value); +void +PciBhtOr32(EFI_PCI_IO_PROTOCOL *PciIo, UINT32 offset, UINT32 value); +void +PciBhtAnd32(EFI_PCI_IO_PROTOCOL *PciIo, UINT32 offset, UINT32 value); +extern void +DbgNull(IN CONST CHAR16 * fmt, ...); + + +#if(0) +#define DbgMsg(arg, ...) Print(L##arg, __VA_ARGS__) +#else +#define DbgMsg(...) DEBUG((DEBUG_INFO, __VA_ARGS__)) +#endif + + +#define PCI_DEV_ID_RJ 0x8320 +#define PCI_DEV_ID_SDS0 0x8420 +#define PCI_DEV_ID_SDS1 0x8421 +#define PCI_DEV_ID_FJ2 0x8520 +#define PCI_DEV_ID_SB0 0x8620 +#define PCI_DEV_ID_SB1 0x8621 + + +// O2/BHT add BAR1 for PCIR mapping registers +// These registers is defined by O2/BHT, but we may follow name definition rule. +#define BHT_PCIRMappingVal (0x200) /* PCI CFG Space Register Mapping Value Register */ +#define BHT_PCIRMappingCtl (0x204) /* PCI CFG Space Register Mapping Control Register */ +#define BHT_PCIRMappingEn (0x208) /* PCI CFG Space Register Mapping Enable Register */ +#define BHT_GPIOCTL (0x210) /* GPIO control register*/ + #endif