Skip to content

Commit 61d7437

Browse files
Raul E RangelUlf Hansson
authored andcommitted
mmc: sdhci-acpi: Fix HS400 tuning for AMDI0040
The AMD eMMC Controller can only use the tuned clock while in HS200 and HS400 mode. If we switch to a different mode, we need to disable the tuned clock. If we have previously performed tuning and switch back to HS200 or HS400, we can re-enable the tuned clock. Previously the tuned clock was not getting disabled when switching to DDR52 which is part of the HS400 tuning sequence. Fixes: 34597a3 ("mmc: sdhci-acpi: Add support for ACPI HID of AMD Controller with HS400") Signed-off-by: Raul E Rangel <rrangel@chromium.org> Acked-by: Adrian Hunter <adrian.hunter@intel.com> Link: https://lore.kernel.org/r/20200819125832.v2.1.Ie8f0689ec9f449203328b37409d1cf06b565f331@changeid Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
1 parent 9123e3a commit 61d7437

1 file changed

Lines changed: 57 additions & 10 deletions

File tree

drivers/mmc/host/sdhci-acpi.c

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,11 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = {
535535
.caps = MMC_CAP_NONREMOVABLE,
536536
};
537537

538+
struct amd_sdhci_host {
539+
bool tuned_clock;
540+
bool dll_enabled;
541+
};
542+
538543
/* AMD sdhci reset dll register. */
539544
#define SDHCI_AMD_RESET_DLL_REGISTER 0x908
540545

@@ -555,26 +560,66 @@ static void sdhci_acpi_amd_hs400_dll(struct sdhci_host *host)
555560
}
556561

557562
/*
558-
* For AMD Platform it is required to disable the tuning
559-
* bit first controller to bring to HS Mode from HS200
560-
* mode, later enable to tune to HS400 mode.
563+
* The initialization sequence for HS400 is:
564+
* HS->HS200->Perform Tuning->HS->HS400
565+
*
566+
* The re-tuning sequence is:
567+
* HS400->DDR52->HS->HS200->Perform Tuning->HS->HS400
568+
*
569+
* The AMD eMMC Controller can only use the tuned clock while in HS200 and HS400
570+
* mode. If we switch to a different mode, we need to disable the tuned clock.
571+
* If we have previously performed tuning and switch back to HS200 or
572+
* HS400, we can re-enable the tuned clock.
573+
*
561574
*/
562575
static void amd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
563576
{
564577
struct sdhci_host *host = mmc_priv(mmc);
578+
struct sdhci_acpi_host *acpi_host = sdhci_priv(host);
579+
struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host);
565580
unsigned int old_timing = host->timing;
581+
u16 val;
566582

567583
sdhci_set_ios(mmc, ios);
568-
if (old_timing == MMC_TIMING_MMC_HS200 &&
569-
ios->timing == MMC_TIMING_MMC_HS)
570-
sdhci_writew(host, 0x9, SDHCI_HOST_CONTROL2);
571-
if (old_timing != MMC_TIMING_MMC_HS400 &&
572-
ios->timing == MMC_TIMING_MMC_HS400) {
573-
sdhci_writew(host, 0x80, SDHCI_HOST_CONTROL2);
574-
sdhci_acpi_amd_hs400_dll(host);
584+
585+
if (old_timing != host->timing && amd_host->tuned_clock) {
586+
if (host->timing == MMC_TIMING_MMC_HS400 ||
587+
host->timing == MMC_TIMING_MMC_HS200) {
588+
val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
589+
val |= SDHCI_CTRL_TUNED_CLK;
590+
sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
591+
} else {
592+
val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
593+
val &= ~SDHCI_CTRL_TUNED_CLK;
594+
sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
595+
}
596+
597+
/* DLL is only required for HS400 */
598+
if (host->timing == MMC_TIMING_MMC_HS400 &&
599+
!amd_host->dll_enabled) {
600+
sdhci_acpi_amd_hs400_dll(host);
601+
amd_host->dll_enabled = true;
602+
}
575603
}
576604
}
577605

606+
static int amd_sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
607+
{
608+
int err;
609+
struct sdhci_host *host = mmc_priv(mmc);
610+
struct sdhci_acpi_host *acpi_host = sdhci_priv(host);
611+
struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host);
612+
613+
amd_host->tuned_clock = false;
614+
615+
err = sdhci_execute_tuning(mmc, opcode);
616+
617+
if (!err && !host->tuning_err)
618+
amd_host->tuned_clock = true;
619+
620+
return err;
621+
}
622+
578623
static const struct sdhci_ops sdhci_acpi_ops_amd = {
579624
.set_clock = sdhci_set_clock,
580625
.set_bus_width = sdhci_set_bus_width,
@@ -602,6 +647,7 @@ static int sdhci_acpi_emmc_amd_probe_slot(struct platform_device *pdev,
602647

603648
host->mmc_host_ops.select_drive_strength = amd_select_drive_strength;
604649
host->mmc_host_ops.set_ios = amd_set_ios;
650+
host->mmc_host_ops.execute_tuning = amd_sdhci_execute_tuning;
605651
return 0;
606652
}
607653

@@ -613,6 +659,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_amd_emmc = {
613659
SDHCI_QUIRK_32BIT_ADMA_SIZE,
614660
.quirks2 = SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
615661
.probe_slot = sdhci_acpi_emmc_amd_probe_slot,
662+
.priv_size = sizeof(struct amd_sdhci_host),
616663
};
617664

618665
struct sdhci_acpi_uid_slot {

0 commit comments

Comments
 (0)