From: "Chang, Rebecca Swee Fun" <[email protected]>
mmc: Baytrail has three SDHC controllers, namely eMMC controller, SDIO controller and SDCARD controller. The controllers can be PCI or ACPI enumerated. Signed-off-by: Chang, Rebecca Swee Fun <[email protected]> --- ...port-for-SDHC-controllers-on-Intel-Baytra.patch | 383 ++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 meta/cfg/kernel-cache/features/valleyisland-io/0015-mmc-Add-support-for-SDHC-controllers-on-Intel-Baytra.patch diff --git a/meta/cfg/kernel-cache/features/valleyisland-io/0015-mmc-Add-support-for-SDHC-controllers-on-Intel-Baytra.patch b/meta/cfg/kernel-cache/features/valleyisland-io/0015-mmc-Add-support-for-SDHC-controllers-on-Intel-Baytra.patch new file mode 100644 index 0000000..f2e155f --- /dev/null +++ b/meta/cfg/kernel-cache/features/valleyisland-io/0015-mmc-Add-support-for-SDHC-controllers-on-Intel-Baytra.patch @@ -0,0 +1,383 @@ +mmc: Add support for SDHC controllers on Intel Valley Island platform + +Valley Island has three SDHC controllers, namely eMMC controller, SDIO controller +and SDCARD controller. The controllers can be PCI or ACPI enumerated. + +Signed-off-by: Chang, Rebecca Swee Fun <[email protected]> +--- + drivers/mmc/core/core.c | 5 ++- + drivers/mmc/core/sdio_bus.c | 20 ++++++++++- + drivers/mmc/host/sdhci-acpi.c | 71 +++++++++++++++++++++++++++++++++------ + drivers/mmc/host/sdhci-pci.c | 73 +++++++++++++++++++++++++++++++++++++++++ + drivers/mmc/host/sdhci.c | 19 +++++++++++ + include/linux/mmc/host.h | 3 ++ + include/linux/mmc/sdhci.h | 4 +++ + 7 files changed, 183 insertions(+), 12 deletions(-) + +diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c +index aaed768..155185f 100644 +--- a/drivers/mmc/core/core.c ++++ b/drivers/mmc/core/core.c +@@ -2223,7 +2223,10 @@ void mmc_start_host(struct mmc_host *host) + { + host->f_init = max(freqs[0], host->f_min); + host->rescan_disable = 0; +- mmc_power_up(host); ++ if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP) ++ mmc_power_off(host); ++ else ++ mmc_power_up(host); + mmc_detect_change(host, 0); + } + +diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c +index 5e57048..8d6bb18 100644 +--- a/drivers/mmc/core/sdio_bus.c ++++ b/drivers/mmc/core/sdio_bus.c +@@ -16,6 +16,7 @@ + #include <linux/export.h> + #include <linux/slab.h> + #include <linux/pm_runtime.h> ++#include <linux/acpi.h> + + #include <linux/mmc/card.h> + #include <linux/mmc/host.h> +@@ -299,6 +300,19 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card) + return func; + } + ++#ifdef CONFIG_ACPI ++static void sdio_acpi_set_handle(struct sdio_func *func) ++{ ++ struct mmc_host *host = func->card->host; ++ u64 addr = (host->slotno << 16) | func->num; ++ ++ ACPI_HANDLE_SET(&func->dev, ++ acpi_get_child(ACPI_HANDLE(host->parent), addr)); ++} ++#else ++static inline void sdio_acpi_set_handle(struct sdio_func *func) {} ++#endif ++ + /* + * Register a new SDIO function with the driver model. + */ +@@ -308,9 +322,12 @@ int sdio_add_func(struct sdio_func *func) + + dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num); + ++ sdio_acpi_set_handle(func); + ret = device_add(&func->dev); +- if (ret == 0) ++ if (ret == 0) { + sdio_func_set_present(func); ++ acpi_dev_pm_attach(&func->dev, false); ++ } + + return ret; + } +@@ -326,6 +343,7 @@ void sdio_remove_func(struct sdio_func *func) + if (!sdio_func_present(func)) + return; + ++ acpi_dev_pm_detach(&func->dev, false); + device_del(&func->dev); + put_device(&func->dev); + } +diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c +index 2592ddd..a0fd8a1 100644 +--- a/drivers/mmc/host/sdhci-acpi.c ++++ b/drivers/mmc/host/sdhci-acpi.c +@@ -87,30 +87,78 @@ static const struct sdhci_ops sdhci_acpi_ops_dflt = { + .enable_dma = sdhci_acpi_enable_dma, + }; + ++static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = { ++ .caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE, ++ .caps2 = MMC_CAP2_HC_ERASE_SZ, ++}; ++ + static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { + .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, + .caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD, +- .flags = SDHCI_ACPI_RUNTIME_PM, + .pm_caps = MMC_PM_KEEP_POWER, + }; + ++static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = { ++}; ++ ++struct sdhci_acpi_uid_slot { ++ const char *hid; ++ const char *uid; ++ const struct sdhci_acpi_slot *slot; ++}; ++ ++static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = { ++ { "80860F14" , "1" , &sdhci_acpi_slot_int_emmc }, ++ { "80860F14" , "3" , &sdhci_acpi_slot_int_sd }, ++ { "INT33BB" , "2" , &sdhci_acpi_slot_int_sdio }, ++ { "INT33C6" , NULL, &sdhci_acpi_slot_int_sdio }, ++ { "PNP0D40" }, ++ { }, ++}; ++ + static const struct acpi_device_id sdhci_acpi_ids[] = { +- { "INT33C6", (kernel_ulong_t)&sdhci_acpi_slot_int_sdio }, +- { "PNP0D40" }, ++ { "80860F14" }, ++ { "INT33BB" }, ++ { "INT33C6" }, ++ { "PNP0D40" }, + { }, + }; + MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids); + +-static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid) ++static const struct sdhci_acpi_slot *sdhci_acpi_get_slot_by_ids(const char *hid, ++ const char *uid) + { +- const struct acpi_device_id *id; +- +- for (id = sdhci_acpi_ids; id->id[0]; id++) +- if (!strcmp(id->id, hid)) +- return (const struct sdhci_acpi_slot *)id->driver_data; ++ const struct sdhci_acpi_uid_slot *u; ++ ++ for (u = sdhci_acpi_uids; u->hid; u++) { ++ if (strcmp(u->hid, hid)) ++ continue; ++ if (!u->uid) ++ return u->slot; ++ if (uid && !strcmp(u->uid, uid)) ++ return u->slot; ++ } + return NULL; + } + ++static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(acpi_handle handle, ++ const char *hid) ++{ ++ const struct sdhci_acpi_slot *slot; ++ struct acpi_device_info *info; ++ const char *uid = NULL; ++ acpi_status status; ++ ++ status = acpi_get_object_info(handle, &info); ++ if (!ACPI_FAILURE(status) && (info->valid & ACPI_VALID_UID)) ++ uid = info->unique_id.string; ++ ++ slot = sdhci_acpi_get_slot_by_ids(hid, uid); ++ ++ kfree(info); ++ return slot; ++} ++ + static int sdhci_acpi_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -148,7 +196,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev) + + c = sdhci_priv(host); + c->host = host; +- c->slot = sdhci_acpi_get_slot(hid); ++ c->slot = sdhci_acpi_get_slot(handle, hid); + c->pdev = pdev; + c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM); + +@@ -195,11 +243,14 @@ static int sdhci_acpi_probe(struct platform_device *pdev) + host->mmc->pm_caps |= c->slot->pm_caps; + } + ++ host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP; ++ + err = sdhci_add_host(host); + if (err) + goto err_free; + + if (c->use_runtime_pm) { ++ pm_runtime_set_active(dev); + pm_suspend_ignore_children(dev, 1); + pm_runtime_set_autosuspend_delay(dev, 50); + pm_runtime_use_autosuspend(dev); +diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c +index c7dd0cb..9f662c6 100644 +--- a/drivers/mmc/host/sdhci-pci.c ++++ b/drivers/mmc/host/sdhci-pci.c +@@ -48,6 +48,12 @@ + + #define MAX_SLOTS 8 + ++#define PCI_DEVICE_ID_INTEL_BYT_EMMC0 0x0F14 /*eMMC4.41*/ ++#define PCI_DEVICE_ID_INTEL_BYT_EMMC1 0x0F50 /*eMMC4.5*/ ++#define PCI_DEVICE_ID_INTEL_BYT_SDIO 0x0F15 ++#define PCI_DEVICE_ID_INTEL_BYT_SD 0x0F16 ++ ++ + struct sdhci_pci_chip; + struct sdhci_pci_slot; + +@@ -304,6 +310,39 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = { + .probe_slot = pch_hc_probe_slot, + }; + ++static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE; ++ slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ; ++ return 0; ++} ++ ++static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE; ++ return 0; ++} ++ ++static const struct sdhci_pci_fixes sdhci_intel_byt_emmc0 = { ++ .allow_runtime_pm = false, ++ .probe_slot = byt_emmc_probe_slot, ++}; ++ ++static const struct sdhci_pci_fixes sdhci_intel_byt_emmc1 = { ++ .allow_runtime_pm = false, ++ .probe_slot = byt_emmc_probe_slot, ++}; ++ ++static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { ++ .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, ++ .allow_runtime_pm = false, ++ .probe_slot = byt_sdio_probe_slot, ++}; ++ ++static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { ++ .quirks2 = SDHCI_QUIRK2_NO_PRESET | SDHCI_QUIRK2_DDR50_LOW_CLOCK, ++}; ++ + /* O2Micro extra registers */ + #define O2_SD_LOCK_WP 0xD3 + #define O2_SD_MULTI_VCC3V 0xEE +@@ -856,6 +895,38 @@ static const struct pci_device_id pci_ids[] = { + }, + + { ++ .vendor = PCI_VENDOR_ID_INTEL, ++ .device = PCI_DEVICE_ID_INTEL_BYT_EMMC0, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc0, ++ }, ++ ++ { ++ .vendor = PCI_VENDOR_ID_INTEL, ++ .device = PCI_DEVICE_ID_INTEL_BYT_EMMC1, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc1, ++ }, ++ ++ { ++ .vendor = PCI_VENDOR_ID_INTEL, ++ .device = PCI_DEVICE_ID_INTEL_BYT_SDIO, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio, ++ }, ++ ++ { ++ .vendor = PCI_VENDOR_ID_INTEL, ++ .device = PCI_DEVICE_ID_INTEL_BYT_SD, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd, ++ }, ++ ++ { + .vendor = PCI_VENDOR_ID_O2, + .device = PCI_DEVICE_ID_O2_8120, + .subvendor = PCI_ANY_ID, +@@ -1279,6 +1350,8 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( + } + + host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; ++ host->mmc->slotno = slotno; ++ host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP; + + ret = sdhci_add_host(host); + if (ret) +diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c +index 6f0bfc0..a6f5c14 100644 +--- a/drivers/mmc/host/sdhci.c ++++ b/drivers/mmc/host/sdhci.c +@@ -1148,6 +1148,15 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) + } + real_div = div; + div >>= 1; ++ ++ if(host->quirks2 & SDHCI_QUIRK2_DDR50_LOW_CLOCK){ ++ /* DDR50 speed at 25MHz and lower */ ++ if (div == 1 && (sdhci_readw(host, SDHCI_HOST_CONTROL2) & ++ SDHCI_CTRL_UHS_DDR50)){ ++ div <<= 1; ++ real_div = (div <<= 1); ++ } ++ } + } + } else { + /* Version 2.00 divisors must be a power of 2. */ +@@ -1968,6 +1977,16 @@ static void sdhci_do_enable_preset_value(struct sdhci_host *host, bool enable) + + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); + ++ if(host->quirks2 & SDHCI_QUIRK2_NO_PRESET){ ++ if(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE){ ++ ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; ++ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); ++ host->flags &= ~SDHCI_PV_ENABLED; ++ } ++ spin_unlock_irqrestore(&host->lock, flags); ++ return; ++ } ++ + /* + * We only enable or disable Preset Value if they are not already + * enabled or disabled respectively. Otherwise, we bail out. +diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h +index 61a10c1..b4a8293 100644 +--- a/include/linux/mmc/host.h ++++ b/include/linux/mmc/host.h +@@ -258,6 +258,7 @@ struct mmc_host { + #define MMC_CAP2_HC_ERASE_SZ (1 << 9) /* High-capacity erase size */ + #define MMC_CAP2_CD_ACTIVE_HIGH (1 << 10) /* Card-detect signal active high */ + #define MMC_CAP2_RO_ACTIVE_HIGH (1 << 11) /* Write-protect signal active high */ ++#define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */ + + mmc_pm_flag_t pm_caps; /* supported pm features */ + +@@ -338,6 +339,8 @@ struct mmc_host { + + unsigned int actual_clock; /* Actual HC clock rate */ + ++ unsigned int slotno; /* used for sdio acpi binding */ ++ + unsigned long private[0] ____cacheline_aligned; + }; + +diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h +index 4bbc330..f53100b 100644 +--- a/include/linux/mmc/sdhci.h ++++ b/include/linux/mmc/sdhci.h +@@ -94,6 +94,10 @@ struct sdhci_host { + #define SDHCI_QUIRK2_HOST_NO_CMD23 (1<<1) + /* The system physically doesn't support 1.8v, even if the host does */ + #define SDHCI_QUIRK2_NO_1_8_V (1<<2) ++/* Controller allows driver to take over preset value */ ++#define SDHCI_QUIRK2_NO_PRESET (1<<3) ++/* Controller needs low clock speed for DDR50 */ ++#define SDHCI_QUIRK2_DDR50_LOW_CLOCK (1<<4) + + int irq; /* Device IRQ */ + void __iomem *ioaddr; /* Mapped address */ +-- +1.7.10.4 + -- 1.7.10.4 _______________________________________________ linux-yocto mailing list [email protected] https://lists.yoctoproject.org/listinfo/linux-yocto
