aboutsummaryrefslogtreecommitdiff
path: root/drivers/mmc/host/sdhci-pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/sdhci-pci.c')
-rw-r--r--drivers/mmc/host/sdhci-pci.c284
1 files changed, 153 insertions, 131 deletions
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index d7d6bc8968d..52c42fcc284 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -27,73 +27,8 @@
#include <linux/mmc/sdhci-pci-data.h>
#include "sdhci.h"
-
-/*
- * PCI device IDs
- */
-#define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809
-#define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a
-#define PCI_DEVICE_ID_INTEL_BYT_EMMC 0x0f14
-#define PCI_DEVICE_ID_INTEL_BYT_SDIO 0x0f15
-#define PCI_DEVICE_ID_INTEL_BYT_SD 0x0f16
-#define PCI_DEVICE_ID_INTEL_BYT_EMMC2 0x0f50
-
-/*
- * PCI registers
- */
-
-#define PCI_SDHCI_IFPIO 0x00
-#define PCI_SDHCI_IFDMA 0x01
-#define PCI_SDHCI_IFVENDOR 0x02
-
-#define PCI_SLOT_INFO 0x40 /* 8 bits */
-#define PCI_SLOT_INFO_SLOTS(x) ((x >> 4) & 7)
-#define PCI_SLOT_INFO_FIRST_BAR_MASK 0x07
-
-#define MAX_SLOTS 8
-
-struct sdhci_pci_chip;
-struct sdhci_pci_slot;
-
-struct sdhci_pci_fixes {
- unsigned int quirks;
- unsigned int quirks2;
- bool allow_runtime_pm;
-
- int (*probe) (struct sdhci_pci_chip *);
-
- int (*probe_slot) (struct sdhci_pci_slot *);
- void (*remove_slot) (struct sdhci_pci_slot *, int);
-
- int (*suspend) (struct sdhci_pci_chip *);
- int (*resume) (struct sdhci_pci_chip *);
-};
-
-struct sdhci_pci_slot {
- struct sdhci_pci_chip *chip;
- struct sdhci_host *host;
- struct sdhci_pci_data *data;
-
- int pci_bar;
- int rst_n_gpio;
- int cd_gpio;
- int cd_irq;
-
- void (*hw_reset)(struct sdhci_host *host);
-};
-
-struct sdhci_pci_chip {
- struct pci_dev *pdev;
-
- unsigned int quirks;
- unsigned int quirks2;
- bool allow_runtime_pm;
- const struct sdhci_pci_fixes *fixes;
-
- int num_slots; /* Slots on controller */
- struct sdhci_pci_slot *slots[MAX_SLOTS]; /* Pointers to host slots */
-};
-
+#include "sdhci-pci.h"
+#include "sdhci-pci-o2micro.h"
/*****************************************************************************\
* *
@@ -290,6 +225,7 @@ static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = {
static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = {
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.allow_runtime_pm = true,
+ .own_cd_for_runtime_pm = true,
};
static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = {
@@ -354,6 +290,30 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
.quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON,
.allow_runtime_pm = true,
+ .own_cd_for_runtime_pm = true,
+};
+
+/* Define Host controllers for Intel Merrifield platform */
+#define INTEL_MRFL_EMMC_0 0
+#define INTEL_MRFL_EMMC_1 1
+
+static int intel_mrfl_mmc_probe_slot(struct sdhci_pci_slot *slot)
+{
+ if ((PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFL_EMMC_0) &&
+ (PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFL_EMMC_1))
+ /* SD support is not ready yet */
+ return -ENODEV;
+
+ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
+ MMC_CAP_1_8V_DDR;
+
+ return 0;
+}
+
+static const struct sdhci_pci_fixes sdhci_intel_mrfl_mmc = {
+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+ .quirks2 = SDHCI_QUIRK2_BROKEN_HS200,
+ .probe_slot = intel_mrfl_mmc_probe_slot,
};
/* O2Micro extra registers */
@@ -365,65 +325,6 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
#define O2_SD_ADMA2 0xE7
#define O2_SD_INF_MOD 0xF1
-static int o2_probe(struct sdhci_pci_chip *chip)
-{
- int ret;
- u8 scratch;
-
- switch (chip->pdev->device) {
- case PCI_DEVICE_ID_O2_8220:
- case PCI_DEVICE_ID_O2_8221:
- case PCI_DEVICE_ID_O2_8320:
- case PCI_DEVICE_ID_O2_8321:
- /* This extra setup is required due to broken ADMA. */
- ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
- if (ret)
- return ret;
- scratch &= 0x7f;
- pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
-
- /* Set Multi 3 to VCC3V# */
- pci_write_config_byte(chip->pdev, O2_SD_MULTI_VCC3V, 0x08);
-
- /* Disable CLK_REQ# support after media DET */
- ret = pci_read_config_byte(chip->pdev, O2_SD_CLKREQ, &scratch);
- if (ret)
- return ret;
- scratch |= 0x20;
- pci_write_config_byte(chip->pdev, O2_SD_CLKREQ, scratch);
-
- /* Choose capabilities, enable SDMA. We have to write 0x01
- * to the capabilities register first to unlock it.
- */
- ret = pci_read_config_byte(chip->pdev, O2_SD_CAPS, &scratch);
- if (ret)
- return ret;
- scratch |= 0x01;
- pci_write_config_byte(chip->pdev, O2_SD_CAPS, scratch);
- pci_write_config_byte(chip->pdev, O2_SD_CAPS, 0x73);
-
- /* Disable ADMA1/2 */
- pci_write_config_byte(chip->pdev, O2_SD_ADMA1, 0x39);
- pci_write_config_byte(chip->pdev, O2_SD_ADMA2, 0x08);
-
- /* Disable the infinite transfer mode */
- ret = pci_read_config_byte(chip->pdev, O2_SD_INF_MOD, &scratch);
- if (ret)
- return ret;
- scratch |= 0x08;
- pci_write_config_byte(chip->pdev, O2_SD_INF_MOD, scratch);
-
- /* Lock WP */
- ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
- if (ret)
- return ret;
- scratch |= 0x80;
- pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
- }
-
- return 0;
-}
-
static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
{
u8 scratch;
@@ -614,7 +515,10 @@ static int jmicron_resume(struct sdhci_pci_chip *chip)
}
static const struct sdhci_pci_fixes sdhci_o2 = {
- .probe = o2_probe,
+ .probe = sdhci_pci_o2_probe,
+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+ .probe_slot = sdhci_pci_o2_probe_slot,
+ .resume = sdhci_pci_o2_resume,
};
static const struct sdhci_pci_fixes sdhci_jmicron = {
@@ -706,6 +610,18 @@ static const struct sdhci_pci_fixes sdhci_via = {
.probe = via_probe,
};
+static int rtsx_probe_slot(struct sdhci_pci_slot *slot)
+{
+ slot->host->mmc->caps2 |= MMC_CAP2_HS200;
+ return 0;
+}
+
+static const struct sdhci_pci_fixes sdhci_rtsx = {
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
+ SDHCI_QUIRK2_BROKEN_DDR50,
+ .probe_slot = rtsx_probe_slot,
+};
+
static const struct pci_device_id pci_ids[] = {
{
.vendor = PCI_VENDOR_ID_RICOH,
@@ -828,6 +744,14 @@ static const struct pci_device_id pci_ids[] = {
},
{
+ .vendor = PCI_VENDOR_ID_REALTEK,
+ .device = 0x5250,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_rtsx,
+ },
+
+ {
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_MRST_SD0,
.subvendor = PCI_ANY_ID,
@@ -939,6 +863,54 @@ static const struct pci_device_id pci_ids[] = {
.driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
},
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_CLV_SDIO0,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sd,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_CLV_SDIO1,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_CLV_SDIO2,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_CLV_EMMC0,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_CLV_EMMC1,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_MRFL_MMC,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_mrfl_mmc,
+ },
{
.vendor = PCI_VENDOR_ID_O2,
.device = PCI_DEVICE_ID_O2_8120,
@@ -979,6 +951,46 @@ static const struct pci_device_id pci_ids[] = {
.driver_data = (kernel_ulong_t)&sdhci_o2,
},
+ {
+ .vendor = PCI_VENDOR_ID_O2,
+ .device = PCI_DEVICE_ID_O2_FUJIN2,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_o2,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_O2,
+ .device = PCI_DEVICE_ID_O2_SDS0,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_o2,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_O2,
+ .device = PCI_DEVICE_ID_O2_SDS1,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_o2,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_O2,
+ .device = PCI_DEVICE_ID_O2_SEABIRD0,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_o2,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_O2,
+ .device = PCI_DEVICE_ID_O2_SEABIRD1,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_o2,
+ },
+
{ /* Generic SD host controller */
PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
},
@@ -1019,7 +1031,7 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host)
return 0;
}
-static int sdhci_pci_bus_width(struct sdhci_host *host, int width)
+static void sdhci_pci_set_bus_width(struct sdhci_host *host, int width)
{
u8 ctrl;
@@ -1040,8 +1052,6 @@ static int sdhci_pci_bus_width(struct sdhci_host *host, int width)
}
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-
- return 0;
}
static void sdhci_pci_gpio_hw_reset(struct sdhci_host *host)
@@ -1068,8 +1078,11 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)
}
static const struct sdhci_ops sdhci_pci_ops = {
+ .set_clock = sdhci_set_clock,
.enable_dma = sdhci_pci_enable_dma,
- .platform_bus_width = sdhci_pci_bus_width,
+ .set_bus_width = sdhci_pci_set_bus_width,
+ .reset = sdhci_reset,
+ .set_uhs_signaling = sdhci_set_uhs_signaling,
.hw_reset = sdhci_pci_hw_reset,
};
@@ -1381,6 +1394,15 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
sdhci_pci_add_own_cd(slot);
+ /*
+ * Check if the chip needs a separate GPIO for card detect to wake up
+ * from runtime suspend. If it is not there, don't allow runtime PM.
+ * Note sdhci_pci_add_own_cd() sets slot->cd_gpio to -EINVAL on failure.
+ */
+ if (chip->fixes && chip->fixes->own_cd_for_runtime_pm &&
+ !gpio_is_valid(slot->cd_gpio))
+ chip->allow_runtime_pm = false;
+
return slot;
remove: