OSDN Git Service

mmc: sdhci-acpi: Add support for ACPI HID of AMD Controller with HS400
authorShah Nehal-Bakulchandra <Nehal-bakulchandra.Shah@amd.com>
Fri, 1 Dec 2017 10:08:52 +0000 (15:38 +0530)
committerUlf Hansson <ulf.hansson@linaro.org>
Mon, 11 Dec 2017 11:48:07 +0000 (12:48 +0100)
This patch supports HS400 for AMD upcoming emmc 5.0 controller.The
HS400 and HS200 mode requires hardware work around also. This patch
adds the quirks for the same.

Signed-off-by: Nehal-bakulchandra Shah <Nehal-bakulchandra.Shah@amd.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/sdhci-acpi.c

index b988997..1b1ce80 100644 (file)
@@ -446,6 +446,83 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = {
        .caps    = MMC_CAP_NONREMOVABLE,
 };
 
+/* AMD sdhci reset dll register. */
+#define SDHCI_AMD_RESET_DLL_REGISTER    0x908
+
+static int amd_select_drive_strength(struct mmc_card *card,
+                                    unsigned int max_dtr, int host_drv,
+                                    int card_drv, int *drv_type)
+{
+       return MMC_SET_DRIVER_TYPE_A;
+}
+
+static void sdhci_acpi_amd_hs400_dll(struct sdhci_host *host)
+{
+       /* AMD Platform requires dll setting */
+       sdhci_writel(host, 0x40003210, SDHCI_AMD_RESET_DLL_REGISTER);
+       usleep_range(10, 20);
+       sdhci_writel(host, 0x40033210, SDHCI_AMD_RESET_DLL_REGISTER);
+}
+
+/*
+ * 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.
+ */
+static void amd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+       unsigned int old_timing = host->timing;
+
+       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);
+       }
+}
+
+static const struct sdhci_ops sdhci_acpi_ops_amd = {
+       .set_clock      = sdhci_set_clock,
+       .set_bus_width  = sdhci_set_bus_width,
+       .reset          = sdhci_reset,
+       .set_uhs_signaling = sdhci_set_uhs_signaling,
+};
+
+static const struct sdhci_acpi_chip sdhci_acpi_chip_amd = {
+       .ops = &sdhci_acpi_ops_amd,
+};
+
+static int sdhci_acpi_emmc_amd_probe_slot(struct platform_device *pdev,
+                                         const char *hid, const char *uid)
+{
+       struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
+       struct sdhci_host *host   = c->host;
+
+       sdhci_read_caps(host);
+       if (host->caps1 & SDHCI_SUPPORT_DDR50)
+               host->mmc->caps = MMC_CAP_1_8V_DDR;
+
+       if ((host->caps1 & SDHCI_SUPPORT_SDR104) &&
+           (host->mmc->caps & MMC_CAP_1_8V_DDR))
+               host->mmc->caps2 = MMC_CAP2_HS400_1_8V;
+
+       host->mmc_host_ops.select_drive_strength = amd_select_drive_strength;
+       host->mmc_host_ops.set_ios = amd_set_ios;
+       return 0;
+}
+
+static const struct sdhci_acpi_slot sdhci_acpi_slot_amd_emmc = {
+       .chip   = &sdhci_acpi_chip_amd,
+       .caps   = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
+       .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_32BIT_DMA_SIZE |
+                       SDHCI_QUIRK_32BIT_ADMA_SIZE,
+       .probe_slot     = sdhci_acpi_emmc_amd_probe_slot,
+};
+
 struct sdhci_acpi_uid_slot {
        const char *hid;
        const char *uid;
@@ -469,6 +546,7 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
        { "PNP0D40"  },
        { "QCOM8051", NULL, &sdhci_acpi_slot_qcom_sd_3v },
        { "QCOM8052", NULL, &sdhci_acpi_slot_qcom_sd },
+       { "AMDI0040", NULL, &sdhci_acpi_slot_amd_emmc },
        { },
 };
 
@@ -485,6 +563,7 @@ static const struct acpi_device_id sdhci_acpi_ids[] = {
        { "PNP0D40"  },
        { "QCOM8051" },
        { "QCOM8052" },
+       { "AMDI0040" },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids);