sdmmc: fix UHS-I tuning init for SD cards

This commit is contained in:
Michael Scire 2020-11-18 08:21:49 -08:00 committed by SciresM
parent 512fc8f9b1
commit b96b162b0b
4 changed files with 7 additions and 49 deletions

View file

@ -33,8 +33,8 @@
//#define AMS_SDMMC_USE_OS_TIMER
#define AMS_SDMMC_USE_UTIL_TIMER
//#define AMS_SDMMC_ENABLE_MMC_HS400
#define AMS_SDMMC_ENABLE_SD_UHS_I
#define AMS_SDMMC_SET_PLLC4_BASE
//#define AMS_SDMMC_ENABLE_SD_UHS_I
//#define AMS_SDMMC_SET_PLLC4_BASE
//#define AMS_SDMMC_USE_SD_CARD_DETECTOR
#elif defined(ATMOSPHERE_IS_MESOSPHERE)

View file

@ -264,9 +264,6 @@ namespace ams::sdmmc::impl::ClockResetController::reg {
/* Check that we have registers we can write to. */
AMS_ABORT_UNLESS(g_clkrst_registers_address != 0);
AMS_LOG("Setting Clock source: target = %u, actual = %u, CLK_SOURCE = %08x\n", target_frequency_khz, *out_actual_frequency_khz, clk_m | static_cast<u32>(n));
AMS_LOG("PLLC4_BASE: %08x\n", ams::reg::Read(g_clkrst_registers_address + CLK_RST_CONTROLLER_PLLC4_BASE));
/* Update the clock source. */
switch (module) {
case Module_Sdmmc1: ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1, clk_m | static_cast<u32>(n)); break;

View file

@ -494,11 +494,9 @@ namespace ams::sdmmc::impl {
/* Check that we're in 4bit bus mode. */
IHostController *hc = BaseDeviceAccessor::GetHostController();
R_UNLESS(hc->GetBusWidth() == BusWidth_4Bit, sdmmc::ResultSdCardNot4BitBusWidthAtUhsIMode());
AMS_LOG("%s\n", "BusWidth good\n");
/* Determine what speed mode/access mode we should switch to. */
R_TRY(this->IssueCommandCheckSupportedFunction(wb, wb_size));
AMS_LOG("%s\n", "IssueCommandCheckSupportedFunction\n");
SwitchFunctionAccessMode target_am;
SpeedMode target_sm;
if (max_sm == SpeedMode_SdCardSdr104 && IsSupportedAccessMode(static_cast<const u8 *>(wb), SwitchFunctionAccessMode_Sdr104)) {
@ -510,21 +508,16 @@ namespace ams::sdmmc::impl {
} else {
return sdmmc::ResultSdCardNotSupportSdr104AndSdr50();
}
AMS_LOG("Try Switch to %u %u\n", (u32)target_am, (u32)target_sm);
/* Switch the access mode. */
R_TRY(this->SwitchAccessMode(target_am, wb, wb_size));
AMS_LOG("%s\n", "SwitchAccessMode\n");
/* Set the host controller speed mode and perform tuning using command index 19. */
R_TRY(hc->SetSpeedMode(target_sm));
AMS_LOG("%s\n", "SetSpeedMode\n");
R_TRY(hc->Tuning(target_sm, 19));
AMS_LOG("%s\n", "Tuning\n");
/* Check status. */
R_TRY(BaseDeviceAccessor::IssueCommandSendStatus());
AMS_LOG("%s\n", "IssueCommandSendStatus\n");
return ResultSuccess();
}
@ -580,93 +573,65 @@ namespace ams::sdmmc::impl {
/* Wait 1ms for configuration to take. */
WaitMicroSeconds(1000);
AMS_LOG("%s\n", "Did hc->Startup()\n");
/* Wait an additional 74 clocks for configuration to take. */
WaitClocks(74, hc->GetDeviceClockFrequencyKHz());
AMS_LOG("%s\n", "Wait 74 clocks\n");
/* Go to idle state. */
R_TRY(BaseDeviceAccessor::IssueCommandGoIdleState());
AMS_LOG("%s\n", "Go Idle State\n");
/* Check whether the spec is under 2.0. */
bool spec_under_2 = false;
R_TRY_CATCH(this->IssueCommandSendIfCond()) {
R_CATCH(sdmmc::ResultResponseTimeoutError) { spec_under_2 = true; }
} R_END_TRY_CATCH;
AMS_LOG("%s\n", "Send If Cond\n");
/* Set the rca to 0. */
this->sd_card_device.SetRca(0);
AMS_LOG("%s\n", "SetRca\n");
/* Go to ready state. */
const bool can_use_uhs_i_mode = (max_bw != BusWidth_1Bit) && (max_sm == SpeedMode_SdCardSdr104 || max_sm == SpeedMode_SdCardSdr50);
const bool uhs_i_supported = hc->IsSupportedTuning() && hc->IsSupportedBusPower(BusPower_1_8V);
R_TRY(this->ChangeToReadyState(spec_under_2, can_use_uhs_i_mode && uhs_i_supported));
AMS_LOG("%s\n", "ChangeToReadyState\n");
/* Get the CID. */
R_TRY(BaseDeviceAccessor::IssueCommandAllSendCid(wb, wb_size));
this->sd_card_device.SetCid(wb, wb_size);
AMS_LOG("%s\n", "IssueCommandAllSendCid\n");
/* Go to stby state and get the RCA. */
R_TRY(this->ChangeToStbyStateAndGetRca());
AMS_LOG("%s\n", "ChangeToStbyStateAndGetRca\n");
/* Get the CSD. */
R_TRY(BaseDeviceAccessor::IssueCommandSendCsd(wb, wb_size));
this->sd_card_device.SetCsd(wb, wb_size);
AMS_LOG("%s\n", "IssueCommandSendCsd\n");
R_TRY(this->SetMemoryCapacity(wb));
AMS_LOG("%s\n", "SetMemoryCapacity\n");
/* Set the host controller speed mode to default if we're not in uhs i mode. */
if (!this->sd_card_device.IsUhsIMode()) {
R_TRY(hc->SetSpeedMode(SpeedMode_SdCardDefaultSpeed));
}
AMS_LOG("%s\n", "SetSpeedMode\n");
/* Issue select card command. */
R_TRY(BaseDeviceAccessor::IssueCommandSelectCard());
AMS_LOG("%s\n", "IssueCommandSelectCard\n");
/* Set block length to sector size. */
R_TRY(BaseDeviceAccessor::IssueCommandSetBlockLenToSectorSize());
AMS_LOG("%s\n", "IssueCommandSetBlockLenToSectorSize\n");
/* Try to disconnect dat3 pullup resistor. */
TryDisconnectDat3PullUpResistor();
AMS_LOG("%s\n", "TryDisconnectDat3PullUpResistor\n");
/* Get the SCR. */
R_TRY(this->GetScr(wb, wb_size));
const u8 sd_bw = GetSdBusWidths(static_cast<const u8 *>(wb));
const bool spec_under_1_1 = IsLessThanSpecification1_1(static_cast<const u8 *>(wb));
AMS_LOG("%s\n", "GetScr\n");
/* Extend the bus width to the largest that we can. */
R_TRY(this->ExtendBusWidth(max_bw, sd_bw));
AMS_LOG("%s\n", "ExtendBusWidth\n");
/* Extend the bus speed to as fast as we can. */
if (this->sd_card_device.IsUhsIMode()) {
R_TRY(this->ExtendBusSpeedAtUhsIMode(max_sm, wb, wb_size));
AMS_LOG("%s\n", "ExtendBusSpeedAtUhsIMode\n");
} else {
R_TRY(this->ExtendBusSpeedAtNonUhsIMode(max_sm, spec_under_1_1, wb, wb_size));
AMS_LOG("%s\n", "ExtendBusSpeedAtNonUhsIMode\n");
}
/* Enable power saving. */
@ -717,8 +682,6 @@ namespace ams::sdmmc::impl {
return ResultSuccess();
}
AMS_LOG("Startup Failed, Result = %08x\n", result.GetValue());
/* Check if we were removed. */
AMS_SDMMC_CHECK_SD_CARD_REMOVED();

View file

@ -532,6 +532,11 @@ namespace ams::sdmmc::impl {
/* Set the offsets. */
reg::ReadWrite(this->sdmmc_registers->auto_cal_config, SD_REG_BITS_VALUE(AUTO_CAL_CONFIG_AUTO_CAL_PD_OFFSET, pd),
SD_REG_BITS_VALUE(AUTO_CAL_CONFIG_AUTO_CAL_PU_OFFSET, pu));
/* Wait for 1ms to ensure that our configuration takes. */
/* NOTE/HACK: Nintendo does not (need) to do this, but they use SvcSleepThread for waits. */
/* It's unclear why this wait is necessary, but not doing it causes drive strength calibration to fail if done immediately afterwards. */
util::WaitMicroSeconds(1000);
}
void SdmmcController::CalibrateDriveStrength(BusPower bus_power) {
@ -578,8 +583,6 @@ namespace ams::sdmmc::impl {
this->drive_strength_calibration_status = sdmmc::ResultSdmmcCompOpen();
}
AMS_LOG("[sdmmc] IsSocMariko(): %d\n", IsSocMariko());
AMS_LOG("[sdmmc] AUTO_CAL_STATUS: %08x\n", reg::Read(this->sdmmc_registers->auto_cal_status));
break;
}
@ -856,17 +859,12 @@ namespace ams::sdmmc::impl {
if (i >= num_tries) {
break;
}
++i;
if (reg::HasValue(this->sdmmc_registers->sd_host_standard_registers.host_control2, SD_REG_BITS_ENUM(HOST_CONTROL2_EXECUTE_TUNING, TUNING_COMPLETED))) {
break;
}
}
AMS_LOG("normal_status: %08x\n", reg::Read(this->sdmmc_registers->sd_host_standard_registers.normal_int_status));
AMS_LOG("error_status: %08x\n", reg::Read(this->sdmmc_registers->sd_host_standard_registers.error_int_status));
AMS_LOG("HOST_CONTROL2: %08x\n", reg::Read(this->sdmmc_registers->sd_host_standard_registers.host_control2));
/* Check if we're using the tuned clock. */
R_UNLESS(reg::HasValue(this->sdmmc_registers->sd_host_standard_registers.host_control2, SD_REG_BITS_ENUM(HOST_CONTROL2_SAMPLING_CLOCK, USING_TUNED_CLOCK)), sdmmc::ResultTuningFailed());