MdeModulePkg/SdMmcPciHcDxe: Add UhsSignaling to SdMmcOverride protocol

Some SD Host Controllers use different values in Host Control 2 Register
to select UHS Mode. This patch adds a new UhsSignaling type routine to
the NotifyPhase of the SdMmcOverride protocol.

UHS signaling configuration is moved to a common, default routine
(SdMmcHcUhsSignaling). After it is executed, the protocol producer
can override the values if needed.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Hao Wu <hao.a.wu@intel.com>
This commit is contained in:
Tomasz Michalec 2018-11-10 07:01:25 +08:00 committed by Hao Wu
parent 49c9953425
commit a4708009cc
5 changed files with 181 additions and 60 deletions

View File

@ -740,10 +740,13 @@ EmmcSwitchToHighSpeed (
IN UINT8 BusWidth
)
{
EFI_STATUS Status;
UINT8 HsTiming;
UINT8 HostCtrl1;
UINT8 HostCtrl2;
EFI_STATUS Status;
UINT8 HsTiming;
UINT8 HostCtrl1;
SD_MMC_BUS_MODE Timing;
SD_MMC_HC_PRIVATE_DATA *Private;
Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, IsDdr, BusWidth);
if (EFI_ERROR (Status)) {
@ -758,25 +761,15 @@ EmmcSwitchToHighSpeed (
return Status;
}
//
// Clean UHS Mode Select field of Host Control 2 reigster before update
//
HostCtrl2 = (UINT8)~0x7;
Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Set UHS Mode Select field of Host Control 2 reigster to SDR12/25/50
//
if (IsDdr) {
HostCtrl2 = BIT2;
Timing = SdMmcMmcHsDdr;
} else if (ClockFreq == 52) {
HostCtrl2 = BIT0;
Timing = SdMmcMmcHsSdr;
} else {
HostCtrl2 = 0;
Timing = SdMmcMmcLegacy;
}
Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, Timing);
if (EFI_ERROR (Status)) {
return Status;
}
@ -814,10 +807,13 @@ EmmcSwitchToHS200 (
IN UINT8 BusWidth
)
{
EFI_STATUS Status;
UINT8 HsTiming;
UINT8 HostCtrl2;
UINT16 ClockCtrl;
EFI_STATUS Status;
UINT8 HsTiming;
UINT16 ClockCtrl;
SD_MMC_BUS_MODE Timing;
SD_MMC_HC_PRIVATE_DATA *Private;
Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
if ((BusWidth != 4) && (BusWidth != 8)) {
return EFI_INVALID_PARAMETER;
@ -837,22 +833,14 @@ EmmcSwitchToHS200 (
if (EFI_ERROR (Status)) {
return Status;
}
//
// Clean UHS Mode Select field of Host Control 2 reigster before update
//
HostCtrl2 = (UINT8)~0x7;
Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Set UHS Mode Select field of Host Control 2 reigster to SDR104
//
HostCtrl2 = BIT0 | BIT1;
Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
Timing = SdMmcMmcHs200;
Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, Timing);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Wait Internal Clock Stable in the Clock Control register to be 1 before set SD Clock Enable bit
//
@ -910,9 +898,12 @@ EmmcSwitchToHS400 (
IN UINT32 ClockFreq
)
{
EFI_STATUS Status;
UINT8 HsTiming;
UINT8 HostCtrl2;
EFI_STATUS Status;
UINT8 HsTiming;
SD_MMC_BUS_MODE Timing;
SD_MMC_HC_PRIVATE_DATA *Private;
Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, ClockFreq, 8);
if (EFI_ERROR (Status)) {
@ -933,19 +924,10 @@ EmmcSwitchToHS400 (
if (EFI_ERROR (Status)) {
return Status;
}
//
// Clean UHS Mode Select field of Host Control 2 reigster before update
//
HostCtrl2 = (UINT8)~0x7;
Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Set UHS Mode Select field of Host Control 2 reigster to HS400
//
HostCtrl2 = BIT0 | BIT2;
Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
Timing = SdMmcMmcHs400;
Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, Timing);
if (EFI_ERROR (Status)) {
return Status;
}

View File

@ -784,8 +784,8 @@ SdCardSetBusMode (
UINT8 BusWidth;
UINT8 AccessMode;
UINT8 HostCtrl1;
UINT8 HostCtrl2;
UINT8 SwitchResp[64];
SD_MMC_BUS_MODE Timing;
SD_MMC_HC_PRIVATE_DATA *Private;
Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
@ -817,18 +817,23 @@ SdCardSetBusMode (
if (S18A && (Capability->Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) {
ClockFreq = 208;
AccessMode = 3;
Timing = SdMmcUhsSdr104;
} else if (S18A && (Capability->Sdr50 != 0) && ((SwitchResp[13] & BIT2) != 0)) {
ClockFreq = 100;
AccessMode = 2;
Timing = SdMmcUhsSdr50;
} else if (S18A && (Capability->Ddr50 != 0) && ((SwitchResp[13] & BIT4) != 0)) {
ClockFreq = 50;
AccessMode = 4;
Timing = SdMmcUhsDdr50;
} else if ((SwitchResp[13] & BIT1) != 0) {
ClockFreq = 50;
AccessMode = 1;
Timing = SdMmcUhsSdr25;
} else {
ClockFreq = 25;
AccessMode = 0;
Timing = SdMmcUhsSdr12;
}
Status = SdCardSwitch (PassThru, Slot, AccessMode, 0xF, 0xF, 0xF, TRUE, SwitchResp);
@ -854,13 +859,7 @@ SdCardSetBusMode (
}
}
HostCtrl2 = (UINT8)~0x7;
Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
if (EFI_ERROR (Status)) {
return Status;
}
HostCtrl2 = AccessMode;
Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, Timing);
if (EFI_ERROR (Status)) {
return Status;
}

View File

@ -1137,6 +1137,95 @@ SdMmcHcInitHost (
return Status;
}
/**
Set SD Host Controler control 2 registry according to selected speed.
@param[in] ControllerHandle The handle of the controller.
@param[in] PciIo The PCI IO protocol instance.
@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 timing is set successfully.
@retval Others The timing isn't set successfully.
**/
EFI_STATUS
SdMmcHcUhsSignaling (
IN EFI_HANDLE ControllerHandle,
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Slot,
IN SD_MMC_BUS_MODE Timing
)
{
EFI_STATUS Status;
UINT8 HostCtrl2;
HostCtrl2 = (UINT8)~SD_MMC_HC_CTRL_UHS_MASK;
Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
if (EFI_ERROR (Status)) {
return Status;
}
switch (Timing) {
case SdMmcUhsSdr12:
HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR12;
break;
case SdMmcUhsSdr25:
HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR25;
break;
case SdMmcUhsSdr50:
HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR50;
break;
case SdMmcUhsSdr104:
HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR104;
break;
case SdMmcUhsDdr50:
HostCtrl2 = SD_MMC_HC_CTRL_UHS_DDR50;
break;
case SdMmcMmcLegacy:
HostCtrl2 = SD_MMC_HC_CTRL_MMC_LEGACY;
break;
case SdMmcMmcHsSdr:
HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS_SDR;
break;
case SdMmcMmcHsDdr:
HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS_DDR;
break;
case SdMmcMmcHs200:
HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS200;
break;
case SdMmcMmcHs400:
HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS400;
break;
default:
HostCtrl2 = 0;
break;
}
Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
if (EFI_ERROR (Status)) {
return Status;
}
if (mOverride != NULL && mOverride->NotifyPhase != NULL) {
Status = mOverride->NotifyPhase (
ControllerHandle,
Slot,
EdkiiSdMmcUhsSignaling,
&Timing
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"%a: SD/MMC uhs signaling notifier callback failed - %r\n",
__FUNCTION__,
Status
));
return Status;
}
}
return EFI_SUCCESS;
}
/**
Turn on/off LED.

View File

@ -62,6 +62,21 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#define SD_MMC_HC_SLOT_INT_STS 0xFC
#define SD_MMC_HC_CTRL_VER 0xFE
//
// SD Host Controller bits to HOST_CTRL2 register
//
#define SD_MMC_HC_CTRL_UHS_MASK 0x0007
#define SD_MMC_HC_CTRL_UHS_SDR12 0x0000
#define SD_MMC_HC_CTRL_UHS_SDR25 0x0001
#define SD_MMC_HC_CTRL_UHS_SDR50 0x0002
#define SD_MMC_HC_CTRL_UHS_SDR104 0x0003
#define SD_MMC_HC_CTRL_UHS_DDR50 0x0004
#define SD_MMC_HC_CTRL_MMC_LEGACY 0x0000
#define SD_MMC_HC_CTRL_MMC_HS_SDR 0x0001
#define SD_MMC_HC_CTRL_MMC_HS_DDR 0x0004
#define SD_MMC_HC_CTRL_MMC_HS200 0x0003
#define SD_MMC_HC_CTRL_MMC_HS400 0x0005
//
// The transfer modes supported by SD Host Controller
// Simplified Spec 3.0 Table 1-2
@ -518,4 +533,23 @@ SdMmcHcInitTimeoutCtrl (
IN UINT8 Slot
);
/**
Set SD Host Controller control 2 registry according to selected speed.
@param[in] ControllerHandle The handle of the controller.
@param[in] PciIo The PCI IO protocol instance.
@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 timing is set successfully.
@retval Others The timing isn't set successfully.
**/
EFI_STATUS
SdMmcHcUhsSignaling (
IN EFI_HANDLE ControllerHandle,
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Slot,
IN SD_MMC_BUS_MODE Timing
);
#endif

View File

@ -26,11 +26,28 @@
typedef struct _EDKII_SD_MMC_OVERRIDE EDKII_SD_MMC_OVERRIDE;
//
// Bus timing modes
//
typedef enum {
SdMmcUhsSdr12,
SdMmcUhsSdr25,
SdMmcUhsSdr50,
SdMmcUhsSdr104,
SdMmcUhsDdr50,
SdMmcMmcLegacy,
SdMmcMmcHsSdr,
SdMmcMmcHsDdr,
SdMmcMmcHs200,
SdMmcMmcHs400,
} SD_MMC_BUS_MODE;
typedef enum {
EdkiiSdMmcResetPre,
EdkiiSdMmcResetPost,
EdkiiSdMmcInitHostPre,
EdkiiSdMmcInitHostPost,
EdkiiSdMmcUhsSignaling,
} EDKII_SD_MMC_PHASE_TYPE;
/**