[linux-yocto] [PATCH 1/2] valleyisland-io: add patch for valley island SDHC controllers support
rebecca.swee.fun.chang at intel.com
rebecca.swee.fun.chang at intel.com
Mon Dec 2 18:51:47 PST 2013
From: "Chang, Rebecca Swee Fun" <rebecca.swee.fun.chang at intel.com>
mmc: 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 <rebecca.swee.fun.chang at intel.com>
---
...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 <rebecca.swee.fun.chang at intel.com>
+---
+ 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
More information about the linux-yocto
mailing list