Re: [PATCH] mmc: sdhci-acpi: Fix HS400 tuning for AMDI0040
From: Adrian Hunter
Date: Wed Aug 19 2020 - 05:05:56 EST
On 19/08/20 1:31 am, Raul E Rangel wrote:
> 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: 34597a3f60b1 ("mmc: sdhci-acpi: Add support for ACPI HID of AMD Controller with HS400")
> Signed-off-by: Raul E Rangel <rrangel@xxxxxxxxxxxx>
If you make amd_sdhci_execute_tuning() static as the robot pointed out:
Acked-by: Adrian Hunter <adrian.hunter@xxxxxxxxx>
> ---
>
> drivers/mmc/host/sdhci-acpi.c | 68 +++++++++++++++++++++++++++++------
> 1 file changed, 58 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
> index 48ecbd0b180d8..5a30920ef595f 100644
> --- a/drivers/mmc/host/sdhci-acpi.c
> +++ b/drivers/mmc/host/sdhci-acpi.c
> @@ -535,6 +535,11 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = {
> .caps = MMC_CAP_NONREMOVABLE,
> };
>
> +struct amd_sdhci_host {
> + bool tuned_clock;
> + bool dll_enabled;
> +};
> +
> /* AMD sdhci reset dll register. */
> #define SDHCI_AMD_RESET_DLL_REGISTER 0x908
>
> @@ -555,26 +560,67 @@ static void sdhci_acpi_amd_hs400_dll(struct sdhci_host *host)
> }
>
> /*
> - * For AMD Platform it is required to disable the tuning
> - * bit first controller to bring to HS Mode from HS200
> - * mode, later enable to tune to HS400 mode.
> + * The initialization sequence for HS400 is:
> + * HS->HS200->Perform Tuning->HS->HS400
> + *
> + * The re-tuning sequence is:
> + * HS400->DDR52->HS->HS200->Perform Tuning->HS->HS400
> + *
> + * 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.
> + *
> */
> static void amd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> {
> struct sdhci_host *host = mmc_priv(mmc);
> + struct sdhci_acpi_host *acpi_host = sdhci_priv(host);
> + struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host);
> unsigned int old_timing = host->timing;
> + u16 val;
>
> sdhci_set_ios(mmc, ios);
> - if (old_timing == MMC_TIMING_MMC_HS200 &&
> - ios->timing == MMC_TIMING_MMC_HS)
> - sdhci_writew(host, 0x9, SDHCI_HOST_CONTROL2);
> - if (old_timing != MMC_TIMING_MMC_HS400 &&
> - ios->timing == MMC_TIMING_MMC_HS400) {
> - sdhci_writew(host, 0x80, SDHCI_HOST_CONTROL2);
> - sdhci_acpi_amd_hs400_dll(host);
> +
> + if (old_timing != host->timing && amd_host->tuned_clock) {
> + if (host->timing == MMC_TIMING_MMC_HS400 ||
> + host->timing == MMC_TIMING_MMC_HS200) {
> + val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> + val |= SDHCI_CTRL_TUNED_CLK;
> + sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
> + } else {
> + val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> + val &= ~SDHCI_CTRL_TUNED_CLK;
> + sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
> + }
> +
> + /* DLL is only required for HS400 */
> + if (host->timing == MMC_TIMING_MMC_HS400 &&
> + !amd_host->dll_enabled) {
> + trace_printk("%s: Enabling DLL\n", __func__);
> + sdhci_acpi_amd_hs400_dll(host);
> + amd_host->dll_enabled = true;
> + }
> }
> }
>
> +int amd_sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
> +{
> + int err;
> + struct sdhci_host *host = mmc_priv(mmc);
> + struct sdhci_acpi_host *acpi_host = sdhci_priv(host);
> + struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host);
> +
> + amd_host->tuned_clock = false;
> +
> + err = sdhci_execute_tuning(mmc, opcode);
> +
> + if (!err && !host->tuning_err)
> + amd_host->tuned_clock = true;
> +
> + return err;
> +}
> +
> static const struct sdhci_ops sdhci_acpi_ops_amd = {
> .set_clock = sdhci_set_clock,
> .set_bus_width = sdhci_set_bus_width,
> @@ -602,6 +648,7 @@ static int sdhci_acpi_emmc_amd_probe_slot(struct platform_device *pdev,
>
> host->mmc_host_ops.select_drive_strength = amd_select_drive_strength;
> host->mmc_host_ops.set_ios = amd_set_ios;
> + host->mmc_host_ops.execute_tuning = amd_sdhci_execute_tuning;
> return 0;
> }
>
> @@ -613,6 +660,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_amd_emmc = {
> SDHCI_QUIRK_32BIT_ADMA_SIZE,
> .quirks2 = SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
> .probe_slot = sdhci_acpi_emmc_amd_probe_slot,
> + .priv_size = sizeof(struct amd_sdhci_host),
> };
>
> struct sdhci_acpi_uid_slot {
>