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

Reply via email to