diff --git a/drivers/sd/dwcmshc/dwcmshc.cpp b/drivers/sd/dwcmshc/dwcmshc.cpp index a743f53..e480669 100644 --- a/drivers/sd/dwcmshc/dwcmshc.cpp +++ b/drivers/sd/dwcmshc/dwcmshc.cpp @@ -1045,6 +1045,10 @@ MshcSlotGetResponse( NT_ASSERTMSG("Invalid response type!", FALSE); } + if (Command->Index == SDCMD_SEND_RELATIVE_ADDR) { + MshcExtension->CardRca = Response[0] >> 16; + } + MSHC_LOG_EXIT(MshcExtension->LogHandle, MshcExtension, "()"); } @@ -1403,20 +1407,6 @@ MshcResetHost( } if (ResetType == SdResetTypeAll) { - // Mask all interrupts, sdport will toggle them as needed. - MshcDisableInterrupts(MshcExtension, MSHC_INT_ALL, MSHC_IDINT_ALL); - - // Global interrupt enable - MshcWriteRegister(MshcExtension, MSHC_CTRL, MSHC_CTRL_INT_ENABLE); - - // Set the max HW timeout for bus operations. - MshcWriteRegister(MshcExtension, MSHC_TMOUT, 0xffffffff); - - // - // Bring the slot in its initial state. - // - MshcSetClock(MshcExtension, 0); - // // WORKAROUND: // In crashdump mode, sdport will switch to an UHS-I mode @@ -1425,11 +1415,28 @@ MshcResetHost( // for the best... // if (!gCrashdumpMode) { + // + // Reset voltages. + // We don't trust sdport to always do it when needed. + // MshcSetVoltage(MshcExtension, SdBusVoltageOff); MshcSetSignalingVoltage(MshcExtension, SdSignalingVoltage33); } + // Disable clock + MshcSetClock(MshcExtension, 0); + + // Reset bus width MshcSetBusWidth(MshcExtension, SdBusWidth1Bit); + + // Mask all interrupts, sdport will toggle them as needed. + MshcDisableInterrupts(MshcExtension, MSHC_INT_ALL, MSHC_IDINT_ALL); + + // Global interrupt enable + MshcWriteRegister(MshcExtension, MSHC_CTRL, MSHC_CTRL_INT_ENABLE); + + // Set the max HW timeout for bus operations. + MshcWriteRegister(MshcExtension, MSHC_TMOUT, 0xffffffff); } // Acknowledge any pending interrupts. @@ -1442,10 +1449,6 @@ MshcResetHost( if ((ResetType == SdResetTypeDat) && MshcExtension->TuningPerformed && (MshcExtension->DataCrcErrorsSinceLastTuning >= MSHC_DCRC_ERROR_RETUNING_THRESHOLD)) { - - MshcExtension->TuningPerformed = FALSE; - MshcExtension->DataCrcErrorsSinceLastTuning = 0; - MSHC_LOG_WARN( MshcExtension->LogHandle, MshcExtension, @@ -1498,12 +1501,14 @@ MshcSetVoltage( Status = PlatformOperations->SetVoltage(MshcExtension, Voltage); } + MshcExtension->CardPowerControlSupported = NT_SUCCESS(Status); + // // Wait 10ms for regulator to stabilize. // SdPortWait(10000); - return Status; + return STATUS_SUCCESS; } _Use_decl_annotations_ @@ -1711,11 +1716,37 @@ MshcSetSignalingVoltage( switch (Voltage) { case SdSignalingVoltage33: + // + // The card should've been power cycled for its signaling level to + // return to 3.3V. If the platform does not support power control and the + // card was already initialized at 1.8V, it's unsafe to change voltage here. + // Stay at the current level, since sdport will not switch to 1.8V again + // if the card responds with S18A = 0 to ACMD41. + // + if ((MshcExtension->SignalingVoltage == SdSignalingVoltage18) && + !MshcExtension->CardPowerControlSupported) { + // + // Issue SEND_STATUS. If it fails, the card was either removed + // or isn't actually initialized yet (RCA won't match -> timeout). + // We will allow the voltage switch only in this case. + // + ULONG StatusRegister = 0; + Status = MshcSendStatusCommand(MshcExtension, &StatusRegister); + if (NT_SUCCESS(Status)) { + MSHC_LOG_WARN( + MshcExtension->LogHandle, + MshcExtension, + "Not changing signaling for current card - power control unsupported!"); + return STATUS_SUCCESS; + } + } Switch18v = FALSE; break; + case SdSignalingVoltage18: Switch18v = TRUE; break; + default: NT_ASSERTMSG("Invalid signaling voltage!", FALSE); return STATUS_INVALID_PARAMETER; @@ -1802,6 +1833,10 @@ MshcSetSignalingVoltage( MshcEnableGlobalInterrupt(MshcExtension, TRUE); } + if (NT_SUCCESS(Status)) { + MshcExtension->SignalingVoltage = Voltage; + } + return Status; } @@ -1817,6 +1852,9 @@ MshcExecuteTuning( Status = STATUS_NOT_IMPLEMENTED; PlatformOperations = MshcExtension->PlatformOperations; + MshcExtension->TuningPerformed = FALSE; + MshcExtension->DataCrcErrorsSinceLastTuning = 0; + if (PlatformOperations->ExecuteTuning != NULL) { Status = PlatformOperations->ExecuteTuning(MshcExtension); } @@ -2821,6 +2859,39 @@ MshcSendStopCommand( return MshcIssueRequestSynchronously(MshcExtension, &Request, 1000000, FALSE); } +_Use_decl_annotations_ +NTSTATUS +MshcSendStatusCommand( + _In_ PMSHC_EXTENSION MshcExtension, + _Out_ PULONG StatusRegister + ) +{ + NTSTATUS Status; + SDPORT_REQUEST Request; + + RtlZeroMemory(&Request, sizeof(Request)); + + Request.Command.Index = SDCMD_SEND_STATUS; + Request.Command.Class = SdCommandClassStandard; + Request.Command.ResponseType = SdResponseTypeR1; + Request.Command.TransferType = SdTransferTypeNone; + Request.Command.Argument = MshcExtension->CardRca << 16; + + // + // Send the command. + // + Request.Type = SdRequestTypeCommandNoTransfer; + + Status = MshcIssueRequestSynchronously(MshcExtension, &Request, 50000, TRUE); + if (!NT_SUCCESS(Status)) { + return Status; + } + + MshcSlotGetResponse(MshcExtension, &Request.Command, StatusRegister); + + return Status; +} + _Use_decl_annotations_ NTSTATUS MshcSendTuningCommand( diff --git a/drivers/sd/dwcmshc/dwcmshc.h b/drivers/sd/dwcmshc/dwcmshc.h index e1cc638..d8af1be 100644 --- a/drivers/sd/dwcmshc/dwcmshc.h +++ b/drivers/sd/dwcmshc/dwcmshc.h @@ -429,8 +429,10 @@ typedef struct _MSHC_IDMAC_DESCRIPTOR { // Standard SD/MMC commands // #define SDCMD_GO_IDLE_STATE 0 +#define SDCMD_SEND_RELATIVE_ADDR 3 #define SDCMD_VOLTAGE_SWITCH 11 #define SDCMD_STOP_TRANSMISSION 12 +#define SDCMD_SEND_STATUS 13 #define SDCMD_GO_INACTIVE_STATE 15 #define SDCMD_SEND_TUNING_BLOCK 19 #define SDCMD_EMMC_SEND_TUNING_BLOCK 21 @@ -544,6 +546,9 @@ struct _MSHC_EXTENSION { // Current bus configuration // BOOLEAN CardInitialized; + BOOLEAN CardPowerControlSupported; + USHORT CardRca; + SDPORT_SIGNALING_VOLTAGE SignalingVoltage; SDPORT_BUS_SPEED BusSpeed; SDPORT_BUS_WIDTH BusWidth; ULONG BusFrequencyKhz; @@ -821,6 +826,13 @@ MshcSendStopCommand( _In_ PMSHC_EXTENSION MshcExtension ); +_IRQL_requires_max_(APC_LEVEL) +NTSTATUS +MshcSendStatusCommand( + _In_ PMSHC_EXTENSION MshcExtension, + _Out_ PULONG StatusRegister + ); + _IRQL_requires_max_(APC_LEVEL) NTSTATUS MshcSendTuningCommand( diff --git a/drivers/sd/dwcmshc/rockchip_ops.cpp b/drivers/sd/dwcmshc/rockchip_ops.cpp index 5688a05..47c0b8d 100644 --- a/drivers/sd/dwcmshc/rockchip_ops.cpp +++ b/drivers/sd/dwcmshc/rockchip_ops.cpp @@ -126,7 +126,7 @@ MshcRockchipSetVoltage( Status); } - return STATUS_SUCCESS; + return Status; } NTSTATUS @@ -150,7 +150,7 @@ MshcRockchipSetSignalingVoltage( Status); } - return STATUS_SUCCESS; + return Status; } NTSTATUS