Index: sys/dev/sdhci/sdhci.c =================================================================== --- sys/dev/sdhci/sdhci.c +++ sys/dev/sdhci/sdhci.c @@ -989,7 +989,7 @@ host_caps |= MMC_CAP_DRIVER_TYPE_C; if (caps2 & SDHCI_CAN_DRIVE_TYPE_D) host_caps |= MMC_CAP_DRIVER_TYPE_D; - slot->host.caps = host_caps; + slot->host.caps |= host_caps; /* Decide if we have usable DMA. */ if (caps & SDHCI_CAN_DO_DMA) Index: sys/dev/sdhci/sdhci_acpi.c =================================================================== --- sys/dev/sdhci/sdhci_acpi.c +++ sys/dev/sdhci/sdhci_acpi.c @@ -45,12 +45,15 @@ #include #include +#include #include #include "mmcbr_if.h" #include "sdhci_if.h" +#define SDHCI_AMD_RESET_DLL_REGISTER 0x908 + static const struct sdhci_acpi_device { const char* hid; int uid; @@ -277,6 +280,10 @@ sc->quirks |= sdhci_quirk_set; sc->slot.quirks = sc->quirks; + if (strcmp(acpi_dev->hid, "AMDI0040") == 0 && + acpi_dev->uid == 0) { + sc->slot.host.caps |= MMC_CAP_MMC_HS400; + } err = sdhci_init_slot(dev, &sc->slot, 0); if (err) { device_printf(dev, "failed to init slot\n"); @@ -360,6 +367,52 @@ sdhci_generic_intr(&sc->slot); } +static inline void +sdhci_acpi_amd_reset_dll(struct sdhci_slot *slot) +{ + sdhci_acpi_write_4(slot->bus, slot, SDHCI_AMD_RESET_DLL_REGISTER, + 0x40003210); + DELAY(20); + sdhci_acpi_write_4(slot->bus, slot, SDHCI_AMD_RESET_DLL_REGISTER, + 0x40033210); +} + +static void +sdhci_acpi_set_uhs_timing(device_t dev, struct sdhci_slot *slot) +{ + const struct sdhci_acpi_device *acpi_dev; + struct mmc_ios *ios; + uint16_t old_timing; + uint16_t hostctrl2; + + acpi_dev = sdhci_acpi_find_device(dev); + if (acpi_dev == NULL) + return; + + ios = &slot->host.ios; + old_timing = sdhci_acpi_read_2(slot->bus, slot, SDHCI_HOST_CONTROL2); + old_timing &= SDHCI_CTRL2_UHS_MASK; + sdhci_generic_set_uhs_timing(dev, slot); + + if (strcmp(acpi_dev->hid,"AMDI0040") == 0 && + acpi_dev->uid == 0) { + if (old_timing == SDHCI_CTRL2_UHS_SDR104 && + ios->timing == bus_timing_hs) { + hostctrl2 = sdhci_acpi_read_2(slot->bus, slot, SDHCI_HOST_CONTROL2); + sdhci_acpi_write_2(slot->bus, slot, SDHCI_HOST_CONTROL2, hostctrl2 & + ~SDHCI_CTRL2_SAMPLING_CLOCK); + } + if (ios->clock > SD_SDR50_MAX && + old_timing != SDHCI_CTRL2_MMC_HS400 && + ios->timing == bus_timing_mmc_hs400) { + hostctrl2 = sdhci_acpi_read_2(slot->bus, slot, SDHCI_HOST_CONTROL2); + sdhci_acpi_write_2(slot->bus, slot, SDHCI_HOST_CONTROL2, hostctrl2 | + SDHCI_CTRL2_SAMPLING_CLOCK); + sdhci_acpi_amd_reset_dll(slot); + } + } +} + static device_method_t sdhci_methods[] = { /* device_if */ DEVMETHOD(device_probe, sdhci_acpi_probe), @@ -392,7 +445,7 @@ DEVMETHOD(sdhci_write_2, sdhci_acpi_write_2), DEVMETHOD(sdhci_write_4, sdhci_acpi_write_4), DEVMETHOD(sdhci_write_multi_4, sdhci_acpi_write_multi_4), - DEVMETHOD(sdhci_set_uhs_timing, sdhci_generic_set_uhs_timing), + DEVMETHOD(sdhci_set_uhs_timing, sdhci_acpi_set_uhs_timing), DEVMETHOD_END };