/******************************************************************************* Copyright (C) 2018 Marvell International Ltd. SPDX-License-Identifier: BSD-2-Clause-Patent *******************************************************************************/ #include "XenonSdMmcOverride.h" STATIC EFI_HANDLE mXenonSdMmcOverrideHandle; STATIC EDKII_SD_MMC_OVERRIDE *mSdMmcOverride; STATIC EFI_STATUS EFIAPI XenonGetSdMmcDesc ( IN EFI_HANDLE ControllerHandle, IN OUT MV_BOARD_SDMMC_DESC *SdMmcDesc ) { EFI_STATUS Status; MV_BOARD_SDMMC_DESC *SdMmcDescs; NON_DISCOVERABLE_DEVICE *Device; MARVELL_BOARD_DESC_PROTOCOL *BoardDescProtocol; UINTN Index; Device = NULL; Status = gBS->OpenProtocol (ControllerHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid, (VOID **) &Device, mXenonSdMmcOverrideHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (EFI_ERROR (Status)) { return Status; } BoardDescProtocol = NULL; Status = gBS->LocateProtocol (&gMarvellBoardDescProtocolGuid, NULL, (VOID **) &BoardDescProtocol); if (EFI_ERROR (Status)) { return Status; } Status = BoardDescProtocol->BoardDescSdMmcGet (BoardDescProtocol, &SdMmcDescs); if (EFI_ERROR (Status)) { return Status; } for (Index = 0; Index < SdMmcDescs->SdMmcDevCount; Index++) { if (SdMmcDescs[Index].SoC->SdMmcBaseAddress == Device->Resources[0].AddrRangeMin) { *SdMmcDesc = SdMmcDescs[Index]; break; } } if (Index == SdMmcDescs->SdMmcDevCount) { return EFI_INVALID_PARAMETER; } return EFI_SUCCESS; } STATIC EFI_STATUS XenonGetPciIo ( IN EFI_HANDLE ControllerHandle, IN OUT EFI_PCI_IO_PROTOCOL **PciIo ) { EFI_STATUS Status; *PciIo = NULL; Status = gBS->OpenProtocol (ControllerHandle, &gEfiPciIoProtocolGuid, (VOID **) PciIo, mXenonSdMmcOverrideHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL); return Status; } /** Set SD Host Controller control 2 registry according to selected speed. @param[in] ControllerHandle The EFI_HANDLE of the controller. @param[in] Slot The slot number of the SD card to send the command to. @param[in] Timing The timing to select. @retval EFI_SUCCESS The override function completed successfully. @retval EFI_NOT_FOUND The specified controller or slot does not exist. **/ STATIC EFI_STATUS XenonSdMmcHcUhsSignaling ( IN EFI_HANDLE ControllerHandle, IN UINT8 Slot, IN SD_MMC_BUS_MODE Timing ) { EFI_PCI_IO_PROTOCOL *PciIo; EFI_STATUS Status; UINT8 HostCtrl2; UINT8 XenonUhsSelect; if (Slot != 0) { return EFI_NOT_FOUND; } // // Update Host Control Register 2 only for HS200/HS400. // switch (Timing) { case SdMmcMmcHs200: XenonUhsSelect = XENON_SD_MMC_HC_CTRL_HS200; break; case SdMmcMmcHs400: XenonUhsSelect = XENON_SD_MMC_HC_CTRL_HS400; break; default: return EFI_SUCCESS; } Status = XenonGetPciIo (ControllerHandle, &PciIo); if (EFI_ERROR (Status)) { return Status; } HostCtrl2 = (UINT8)~UHS_MODE_SELECT_MASK; Status = XenonHcAndMmio (PciIo, Slot, SDHC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); if (EFI_ERROR (Status)) { return Status; } Status = XenonHcOrMmio (PciIo, Slot, SDHC_HOST_CTRL2, sizeof (XenonUhsSelect), &XenonUhsSelect); return Status; } /** Additional operations specific for host controller @param[in] ControllerHandle The EFI_HANDLE of the controller. @param[in] Slot The 0 based slot index. @param[in] Timing The timing which should be set by host controller. @retval EFI_SUCCESS The override function completed successfully. @retval EFI_NOT_FOUND The specified controller or slot does not exist. **/ STATIC EFI_STATUS XenonSwitchClockFreqPost ( IN EFI_HANDLE ControllerHandle, IN UINT8 Slot, IN SD_MMC_BUS_MODE Timing ) { EFI_STATUS Status; MV_BOARD_SDMMC_DESC SdMmcDesc; EFI_PCI_IO_PROTOCOL *PciIo; if (Slot != 0) { return EFI_NOT_FOUND; } Status = XenonGetPciIo (ControllerHandle, &PciIo); if (EFI_ERROR (Status)) { return Status; } Status = XenonGetSdMmcDesc (ControllerHandle, &SdMmcDesc); if (EFI_ERROR (Status)) { return Status; } Status = XenonSetPhy (PciIo, SdMmcDesc.XenonSlowModeEnabled, SdMmcDesc.XenonTuningStepDivisor, Timing); return Status; } /** Override function for SDHCI controller operations @param[in] ControllerHandle The EFI_HANDLE of the controller. @param[in] Slot The 0 based slot index. @param[in] PhaseType The type of operation and whether the hook is invoked right before (pre) or right after (post) @param[in] PhaseData The pointer to a phase-specific data. @retval EFI_SUCCESS The override function completed successfully. @retval EFI_NOT_FOUND The specified controller or slot does not exist. @retval EFI_UNSUPPORTED Nothing has been done in connection of PhaseType @retval EFI_INVALID_PARAMETER PhaseType is invalid **/ STATIC EFI_STATUS EFIAPI XenonSdMmcNotifyPhase ( IN EFI_HANDLE ControllerHandle, IN UINT8 Slot, IN EDKII_SD_MMC_PHASE_TYPE PhaseType, IN OUT VOID *PhaseData ) { EFI_STATUS Status; MV_BOARD_SDMMC_DESC SdMmcDesc; EFI_PCI_IO_PROTOCOL *PciIo; SD_MMC_BUS_MODE *Timing; if (Slot != 0) { return EFI_NOT_FOUND; } switch (PhaseType) { case EdkiiSdMmcInitHostPre: Status = XenonGetPciIo (ControllerHandle, &PciIo); if (EFI_ERROR (Status)) { return Status; } Status = XenonGetSdMmcDesc (ControllerHandle, &SdMmcDesc); if (EFI_ERROR (Status)) { return Status; } Status = XenonInit (PciIo, SdMmcDesc.Xenon1v8Enabled, SdMmcDesc.XenonSlowModeEnabled, SdMmcDesc.XenonTuningStepDivisor); return Status; case EdkiiSdMmcUhsSignaling: if (PhaseData == NULL) { return EFI_INVALID_PARAMETER; } Timing = (SD_MMC_BUS_MODE *)PhaseData; Status = XenonSdMmcHcUhsSignaling (ControllerHandle, Slot, *Timing); if (EFI_ERROR (Status)) { return Status; } break; case EdkiiSdMmcSwitchClockFreqPost: if (PhaseData == NULL) { return EFI_INVALID_PARAMETER; } Timing = (SD_MMC_BUS_MODE *)PhaseData; Status = XenonSwitchClockFreqPost (ControllerHandle, Slot, *Timing); if (EFI_ERROR (Status)) { return Status; } break; default: return EFI_SUCCESS; } return EFI_SUCCESS; } /** Override function for SDHCI capability bits @param[in] ControllerHandle The EFI_HANDLE of the controller. @param[in] Slot The 0 based slot index. @param[in,out] SdMmcHcSlotCapability The SDHCI capability structure. @param[in,out] BaseClkFreq The base clock frequency value that optionally can be updated. @retval EFI_SUCCESS The override function completed successfully. @retval EFI_NOT_FOUND The specified controller or slot does not exist. @retval EFI_INVALID_PARAMETER SdMmcHcSlotCapability is NULL **/ STATIC EFI_STATUS EFIAPI XenonSdMmcCapability ( IN EFI_HANDLE ControllerHandle, IN UINT8 Slot, IN OUT VOID *SdMmcHcSlotCapability, IN OUT UINT32 *BaseClkFreq ) { EFI_STATUS Status; MV_BOARD_SDMMC_DESC SdMmcDesc; UINT64 Capability; if (SdMmcHcSlotCapability == NULL) { return EFI_INVALID_PARAMETER; } if (Slot != 0) { return EFI_NOT_FOUND; } Status = XenonGetSdMmcDesc (ControllerHandle, &SdMmcDesc); if (EFI_ERROR (Status)) { return Status; } Capability = ReadUnaligned64 (SdMmcHcSlotCapability); // // Override capabilities structure according to board configuration. // if (SdMmcDesc.Xenon1v8Enabled) { Capability &= ~(UINT64)(SDHC_CAP_VOLTAGE_33 | SDHC_CAP_VOLTAGE_30); } else { Capability &= ~(UINT64)(SDHC_CAP_SDR104 | SDHC_CAP_DDR50 | SDHC_CAP_SDR50 | SDHC_CAP_HS400 | SDHC_CAP_VOLTAGE_18); } if (!SdMmcDesc.Xenon8BitBusEnabled) { Capability &= ~(UINT64)(SDHC_CAP_BUS_WIDTH8); } if (SdMmcDesc.XenonSlowModeEnabled) { Capability &= ~(UINT64)(SDHC_CAP_SDR104 | SDHC_CAP_DDR50 | SDHC_CAP_HS400); } Capability &= ~(UINT64)(SDHC_CAP_SLOT_TYPE_MASK); Capability |= SdMmcDesc.SlotType << SDHC_CAP_SLOT_TYPE_OFFSET; WriteUnaligned64 (SdMmcHcSlotCapability, Capability); // // Override inappropriate base clock frequency from Capabilities Register 1. // Actual clock speed of Xenon controller is 400MHz. // *BaseClkFreq = XENON_MMC_MAX_CLK / 1000 / 1000; return EFI_SUCCESS; } /** The entry point for Xenon driver, used to install SdMMcOverrideProtocol on the ImageHandle. @param[in] ImageHandle The firmware allocated handle for this driver image. @param[in] SystemTable Pointer to the EFI system table. @retval EFI_SUCCESS Driver loaded. @retval other Driver not loaded. **/ EFI_STATUS EFIAPI InitializeXenonDxe ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; mSdMmcOverride = AllocateZeroPool (sizeof (EDKII_SD_MMC_OVERRIDE)); if (mSdMmcOverride == NULL) { DEBUG ((DEBUG_ERROR, "%a: Cannot allocate memory\n", __FUNCTION__)); return EFI_OUT_OF_RESOURCES; } mSdMmcOverride->Version = EDKII_SD_MMC_OVERRIDE_PROTOCOL_VERSION; mSdMmcOverride->Capability = XenonSdMmcCapability; mSdMmcOverride->NotifyPhase = XenonSdMmcNotifyPhase; Status = gBS->InstallProtocolInterface (&ImageHandle, &gEdkiiSdMmcOverrideProtocolGuid, EFI_NATIVE_INTERFACE, mSdMmcOverride); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: Filed to install SdMmcOverride protocol\n", __FUNCTION__)); return Status; } mXenonSdMmcOverrideHandle = ImageHandle; return Status; }