@@ -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 */
562575static 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+
578623static 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
618665struct sdhci_acpi_uid_slot {
0 commit comments