Skip to content

Commit

Permalink
Silicon/Rockchip: Add SdMmcPciHcDxe-based eMMC driver
Browse files Browse the repository at this point in the history
This replaces the old SdhciHostDxe driver which is quite limited and has some issues around the DMA code.

It supports all speed modes with the exception of HS400ES (requires a few changes in SdMmcPciHcDxe).

Derived from Quartz64-UEFI's EmmcDxe.
  • Loading branch information
mariobalanica committed Jun 27, 2023
1 parent a4b551c commit 0d5f7fe
Show file tree
Hide file tree
Showing 12 changed files with 572 additions and 2 deletions.
251 changes: 251 additions & 0 deletions edk2-rockchip/Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
/** @file
*
* Synopsys DesignWare Cores SDHCI eMMC driver
*
* Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
* Copyright (c) 2022, Patrick Wildt <patrick@blueri.se>
* Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
**/

#include <Library/DebugLib.h>
#include <Library/IoLib.h>
#include <Library/NonDiscoverableDeviceRegistrationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DwcSdhciPlatformLib.h>

#include <Protocol/NonDiscoverableDevice.h>
#include <Protocol/SdMmcOverride.h>

#include "DwcSdhciDxe.h"

#define EMMC_FORCE_HIGH_SPEED FixedPcdGetBool(PcdDwcSdhciForceHighSpeed)

STATIC EFI_HANDLE mSdMmcControllerHandle;

/**
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
EmmcSdMmcCapability (
IN EFI_HANDLE ControllerHandle,
IN UINT8 Slot,
IN OUT VOID *SdMmcHcSlotCapability,
IN OUT UINT32 *BaseClkFreq
)
{
SD_MMC_HC_SLOT_CAP *Capability = SdMmcHcSlotCapability;

if (SdMmcHcSlotCapability == NULL) {
return EFI_INVALID_PARAMETER;
}
if (ControllerHandle != mSdMmcControllerHandle) {
return EFI_NOT_FOUND;
}

Capability->Hs400 = 1;

if (EMMC_FORCE_HIGH_SPEED) {
Capability->BaseClkFreq = 52;
Capability->Sdr50 = 0;
Capability->Ddr50 = 0;
Capability->Sdr104 = 0;
Capability->Hs400 = 0;
}

return EFI_SUCCESS;
}

/**
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,out] 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_INVALID_PARAMETER PhaseType is invalid
**/
STATIC
EFI_STATUS
EFIAPI
EmmcSdMmcNotifyPhase (
IN EFI_HANDLE ControllerHandle,
IN UINT8 Slot,
IN EDKII_SD_MMC_PHASE_TYPE PhaseType,
IN OUT VOID *PhaseData
)
{
SD_MMC_BUS_MODE *Timing;
UINTN MaxClockFreq;
UINT32 Value, i;

DEBUG ((DEBUG_INFO, "%a\n", __FUNCTION__));

if (ControllerHandle != mSdMmcControllerHandle) {
return EFI_SUCCESS;
}

ASSERT (Slot == 0);

switch (PhaseType) {
case EdkiiSdMmcInitHostPost:
/*
* Just before this Notification POWER_CTRL is toggled to power off
* and on the card. On this controller implementation, toggling
* power off also removes SDCLK_ENABLE (BIT2) from from CLOCK_CTRL.
* Since the clock has already been set up prior to the power toggle,
* re-add the SDCLK_ENABLE bit to start the clock.
*/
MmioOr16((UINT32) SD_MMC_HC_CLOCK_CTRL, CLOCK_CTRL_SDCLK_ENABLE);
break;

case EdkiiSdMmcUhsSignaling:
if (PhaseData == NULL) {
return EFI_INVALID_PARAMETER;
}

Timing = (SD_MMC_BUS_MODE *)PhaseData;
if (*Timing == SdMmcMmcHs400) {
/* HS400 uses a non-standard setting */
MmioOr16((UINT32) SD_MMC_HC_HOST_CTRL2, HOST_CTRL2_HS400);
}
break;

case EdkiiSdMmcSwitchClockFreqPost:
if (PhaseData == NULL) {
return EFI_INVALID_PARAMETER;
}

Timing = (SD_MMC_BUS_MODE *)PhaseData;
switch (*Timing) {
case SdMmcMmcHs400:
case SdMmcMmcHs200:
MaxClockFreq = 200000000UL;
break;
case SdMmcMmcHsSdr:
case SdMmcMmcHsDdr:
MaxClockFreq = 52000000UL;
break;
default:
MaxClockFreq = 26000000UL;
break;
}

DwcSdhciSetClockRate (MaxClockFreq);

if (MaxClockFreq <= 52000000UL) {
MmioWrite32 (EMMC_DLL_CTRL, 0);
MmioWrite32 (EMMC_DLL_RXCLK, 0);
MmioWrite32 (EMMC_DLL_TXCLK, 0);
MmioWrite32 (EMMC_DLL_CMDOUT, 0);
MmioWrite32 (EMMC_DLL_STRBIN, EMMC_DLL_DLYENA |
EMMC_DLL_STRBIN_DELAY_NUM_SEL |
EMMC_DLL_STRBIN_DELAY_NUM_DEFAULT << EMMC_DLL_STRBIN_DELAY_NUM_OFFSET);
break;
}

/* Switch to eMMC mode */
MmioOr32 (EMMC_EMMC_CTRL, EMMC_CTRL_CARD_IS_EMMC);

MmioWrite32(EMMC_DLL_CTRL, EMMC_DLL_CTRL_SRST);
gBS->Stall (1);
MmioWrite32(EMMC_DLL_CTRL, 0);

MmioWrite32(EMMC_DLL_CTRL, EMMC_DLL_CTRL_START_POINT_DEFAULT |
EMMC_DLL_CTRL_INCREMENT_DEFAULT | EMMC_DLL_CTRL_START);

for (i = 0; i < 500; i++) {
Value = MmioRead32(EMMC_DLL_STATUS0);
if (Value & EMMC_DLL_STATUS0_DLL_LOCK &&
!(Value & EMMC_DLL_STATUS0_DLL_TIMEOUT)) {
break;
}
gBS->Stall (1);
}

MmioWrite32(EMMC_DLL_RXCLK, EMMC_DLL_DLYENA |
EMMC_DLL_RXCLK_NO_INVERTER);
MmioWrite32(EMMC_DLL_TXCLK, EMMC_DLL_DLYENA |
EMMC_DLL_TXCLK_TAPNUM_DEFAULT | EMMC_DLL_TXCLK_TAPNUM_FROM_SW);
MmioWrite32(EMMC_DLL_STRBIN, EMMC_DLL_DLYENA |
EMMC_DLL_STRBIN_TAPNUM_DEFAULT);
break;

default:
break;
}
return EFI_SUCCESS;
}

STATIC EDKII_SD_MMC_OVERRIDE mSdMmcOverride = {
EDKII_SD_MMC_OVERRIDE_PROTOCOL_VERSION,
EmmcSdMmcCapability,
EmmcSdMmcNotifyPhase,
};

EFI_STATUS
EFIAPI
DwcSdhciDxeInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;

DEBUG ((DEBUG_BLKIO, "%a\n", __FUNCTION__));

/* Start card on 375 kHz */
DwcSdhciSetClockRate (375000UL);

/* Configure pins */
DwcSdhciSetIoMux ();

/* Disable Command Conflict Check */
MmioWrite32 (EMMC_HOST_CTRL3, 0);

/* Disable DLL for identification */
MmioWrite32 (EMMC_DLL_CTRL, 0);
MmioWrite32 (EMMC_DLL_RXCLK, 0);
MmioWrite32 (EMMC_DLL_TXCLK, 0);
MmioWrite32 (EMMC_DLL_STRBIN, 0);

Status = RegisterNonDiscoverableMmioDevice (
NonDiscoverableDeviceTypeSdhci,
NonDiscoverableDeviceDmaTypeNonCoherent,
NULL,
&mSdMmcControllerHandle,
1,
DWC_SDHCI_BASE, 0x10000);
ASSERT_EFI_ERROR (Status);

Handle = NULL;
Status = gBS->InstallProtocolInterface (&Handle,
&gEdkiiSdMmcOverrideProtocolGuid,
EFI_NATIVE_INTERFACE, (VOID **)&mSdMmcOverride);
ASSERT_EFI_ERROR (Status);

return EFI_SUCCESS;
}
93 changes: 93 additions & 0 deletions edk2-rockchip/Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/** @file
*
* Synopsys DesignWare Cores SDHCI eMMC driver
*
* Copyright (c) 2022, Patrick Wildt <patrick@blueri.se>
* Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
**/

#ifndef __DWCSDHCIDXE_H__
#define __DWCSDHCIDXE_H__

#define DWC_SDHCI_BASE PcdGet32 (PcdSdhciDxeBaseAddress)

#define SD_MMC_HC_CLOCK_CTRL (DWC_SDHCI_BASE + 0x2C)
#define SD_MMC_HC_HOST_CTRL2 (DWC_SDHCI_BASE + 0x3E)

// eMMC Registers
#define EMMC_HOST_CTRL3 (DWC_SDHCI_BASE + 0x508)
#define EMMC_EMMC_CTRL (DWC_SDHCI_BASE + 0x52C)
#define EMMC_DLL_CTRL (DWC_SDHCI_BASE + 0x800)
#define EMMC_DLL_RXCLK (DWC_SDHCI_BASE + 0x804)
#define EMMC_DLL_TXCLK (DWC_SDHCI_BASE + 0x808)
#define EMMC_DLL_STRBIN (DWC_SDHCI_BASE + 0x80C)
#define EMMC_DLL_CMDOUT (DWC_SDHCI_BASE + 0x810)
#define EMMC_DLL_STATUS0 (DWC_SDHCI_BASE + 0x840)
#define EMMC_DLL_STATUS1 (DWC_SDHCI_BASE + 0x844)

#define CLOCK_CTRL_SDCLK_ENABLE BIT2

#define HOST_CTRL2_HS400 (BIT2 | BIT1 | BIT0)

#define EMMC_CTRL_CARD_IS_EMMC BIT0

#define EMMC_DLL_CTRL_SRST BIT1
#define EMMC_DLL_CTRL_START BIT0
#define EMMC_DLL_CTRL_START_POINT_DEFAULT (5 << 16)
#define EMMC_DLL_CTRL_INCREMENT_DEFAULT (2 << 8)

#define EMMC_DLL_DLYENA BIT27

#define EMMC_DLL_RXCLK_NO_INVERTER BIT29

#define EMMC_DLL_TXCLK_TAPNUM_DEFAULT (0x10 << 0)
#define EMMC_DLL_TXCLK_TAPNUM_FROM_SW BIT24

#define EMMC_DLL_STRBIN_TAPNUM_DEFAULT (0x3 << 0)
#define EMMC_DLL_STRBIN_DELAY_NUM_SEL BIT26
#define EMMC_DLL_STRBIN_DELAY_NUM_OFFSET 16
#define EMMC_DLL_STRBIN_DELAY_NUM_DEFAULT 0x10

#define EMMC_DLL_STATUS0_DLL_LOCK BIT8
#define EMMC_DLL_STATUS0_DLL_TIMEOUT BIT9

typedef struct {
UINT32 TimeoutFreq : 6; // bit 0:5
UINT32 Reserved : 1; // bit 6
UINT32 TimeoutUnit : 1; // bit 7
UINT32 BaseClkFreq : 8; // bit 8:15
UINT32 MaxBlkLen : 2; // bit 16:17
UINT32 BusWidth8 : 1; // bit 18
UINT32 Adma2 : 1; // bit 19
UINT32 Reserved2 : 1; // bit 20
UINT32 HighSpeed : 1; // bit 21
UINT32 Sdma : 1; // bit 22
UINT32 SuspRes : 1; // bit 23
UINT32 Voltage33 : 1; // bit 24
UINT32 Voltage30 : 1; // bit 25
UINT32 Voltage18 : 1; // bit 26
UINT32 SysBus64V4 : 1; // bit 27
UINT32 SysBus64V3 : 1; // bit 28
UINT32 AsyncInt : 1; // bit 29
UINT32 SlotType : 2; // bit 30:31
UINT32 Sdr50 : 1; // bit 32
UINT32 Sdr104 : 1; // bit 33
UINT32 Ddr50 : 1; // bit 34
UINT32 Reserved3 : 1; // bit 35
UINT32 DriverTypeA : 1; // bit 36
UINT32 DriverTypeC : 1; // bit 37
UINT32 DriverTypeD : 1; // bit 38
UINT32 DriverType4 : 1; // bit 39
UINT32 TimerCount : 4; // bit 40:43
UINT32 Reserved4 : 1; // bit 44
UINT32 TuningSDR50 : 1; // bit 45
UINT32 RetuningMod : 2; // bit 46:47
UINT32 ClkMultiplier : 8; // bit 48:55
UINT32 Reserved5 : 7; // bit 56:62
UINT32 Hs400 : 1; // bit 63
} SD_MMC_HC_SLOT_CAP;

#endif // __DWCSDHCIDXE_H__
49 changes: 49 additions & 0 deletions edk2-rockchip/Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.inf
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#/** @file
#
# Synopsys DesignWare Cores SDHCI eMMC driver
#
# Copyright (c) 2014-2017, Linaro Limited. All rights reserved.
# Copyright (c) 2022, Patrick Wildt <patrick@blueri.se>
# Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
#**/

[Defines]
INF_VERSION = 0x00010019
BASE_NAME = DwcSdhciDxe
FILE_GUID = 4cd3a91b-990e-46a6-b609-9fa5d70d1f5f
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0

ENTRY_POINT = DwcSdhciDxeInitialize

[Sources.common]
DwcSdhciDxe.c

[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
Silicon/Rockchip/RockchipPkg.dec

[LibraryClasses]
UefiDriverEntryPoint
DebugLib
IoLib
NonDiscoverableDeviceRegistrationLib
UefiBootServicesTableLib
DwcSdhciPlatformLib

[Protocols]
gEdkiiNonDiscoverableDeviceProtocolGuid ## PRODUCES
gEdkiiSdMmcOverrideProtocolGuid ## PRODUCES
gEfiCpuArchProtocolGuid
gEfiDevicePathProtocolGuid

[Pcd]
gRockchipTokenSpaceGuid.PcdSdhciDxeBaseAddress
gRockchipTokenSpaceGuid.PcdDwcSdhciForceHighSpeed

[Depex]
TRUE
Loading

0 comments on commit 0d5f7fe

Please sign in to comment.