提交 8f230f45 编写于 作者: T Takashi Iwai 提交者: Chris Ball

mmc: Add support for JMicron 388 SD/MMC controller

JMicron 388 SD/MMC combo controller supports the 1.8V low-voltage for
SD, but MMC doesn't work with the low-voltage, resulting in an error
at probing.

This patch adds the support for multiple voltage mask per device type,
so that SD works with 1.8V while MMC forces 3.3V.  Here new ocr_avail_*
fields for each device are introduced, so that the actual OCR mask is
switched dynamically.

Also, the restriction of low-voltage in core/sd.c is removed when the
bit is allowed explicitly via ocr_avail_sd mask.

This patch was rewritten from scratch based on Aries' original code.
Signed-off-by: NAries Lee <arieslee@jmicron.com>
Signed-off-by: NTakashi Iwai <tiwai@suse.de>
Reviewed-by: NChris Ball <cjb@laptop.org>
Signed-off-by: NChris Ball <cjb@laptop.org>
上级 150ee73d
...@@ -745,6 +745,8 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) ...@@ -745,6 +745,8 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
mmc_attach_bus_ops(host); mmc_attach_bus_ops(host);
if (host->ocr_avail_mmc)
host->ocr_avail = host->ocr_avail_mmc;
/* /*
* We need to get OCR a different way for SPI. * We need to get OCR a different way for SPI.
......
...@@ -772,6 +772,8 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) ...@@ -772,6 +772,8 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
mmc_sd_attach_bus_ops(host); mmc_sd_attach_bus_ops(host);
if (host->ocr_avail_sd)
host->ocr_avail = host->ocr_avail_sd;
/* /*
* We need to get OCR a different way for SPI. * We need to get OCR a different way for SPI.
...@@ -795,7 +797,8 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) ...@@ -795,7 +797,8 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
ocr &= ~0x7F; ocr &= ~0x7F;
} }
if (ocr & MMC_VDD_165_195) { if ((ocr & MMC_VDD_165_195) &&
!(host->ocr_avail_sd & MMC_VDD_165_195)) {
printk(KERN_WARNING "%s: SD card claims to support the " printk(KERN_WARNING "%s: SD card claims to support the "
"incompletely defined 'low voltage range'. This " "incompletely defined 'low voltage range'. This "
"will be ignored.\n", mmc_hostname(host)); "will be ignored.\n", mmc_hostname(host));
......
...@@ -700,6 +700,8 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) ...@@ -700,6 +700,8 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
mmc_attach_bus(host, &mmc_sdio_ops); mmc_attach_bus(host, &mmc_sdio_ops);
if (host->ocr_avail_sdio)
host->ocr_avail = host->ocr_avail_sdio;
/* /*
* Sanity check the voltages that the card claims to * Sanity check the voltages that the card claims to
......
...@@ -272,6 +272,7 @@ static int jmicron_pmos(struct sdhci_pci_chip *chip, int on) ...@@ -272,6 +272,7 @@ static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
static int jmicron_probe(struct sdhci_pci_chip *chip) static int jmicron_probe(struct sdhci_pci_chip *chip)
{ {
int ret; int ret;
u16 mmcdev = 0;
if (chip->pdev->revision == 0) { if (chip->pdev->revision == 0) {
chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR | chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR |
...@@ -293,12 +294,17 @@ static int jmicron_probe(struct sdhci_pci_chip *chip) ...@@ -293,12 +294,17 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
* 2. The MMC interface has a lower subfunction number * 2. The MMC interface has a lower subfunction number
* than the SD interface. * than the SD interface.
*/ */
if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_SD) { if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_SD)
mmcdev = PCI_DEVICE_ID_JMICRON_JMB38X_MMC;
else if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD)
mmcdev = PCI_DEVICE_ID_JMICRON_JMB388_ESD;
if (mmcdev) {
struct pci_dev *sd_dev; struct pci_dev *sd_dev;
sd_dev = NULL; sd_dev = NULL;
while ((sd_dev = pci_get_device(PCI_VENDOR_ID_JMICRON, while ((sd_dev = pci_get_device(PCI_VENDOR_ID_JMICRON,
PCI_DEVICE_ID_JMICRON_JMB38X_MMC, sd_dev)) != NULL) { mmcdev, sd_dev)) != NULL) {
if ((PCI_SLOT(chip->pdev->devfn) == if ((PCI_SLOT(chip->pdev->devfn) ==
PCI_SLOT(sd_dev->devfn)) && PCI_SLOT(sd_dev->devfn)) &&
(chip->pdev->bus == sd_dev->bus)) (chip->pdev->bus == sd_dev->bus))
...@@ -358,11 +364,21 @@ static int jmicron_probe_slot(struct sdhci_pci_slot *slot) ...@@ -358,11 +364,21 @@ static int jmicron_probe_slot(struct sdhci_pci_slot *slot)
slot->host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; slot->host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
} }
/* JM388 MMC doesn't support 1.8V while SD supports it */
if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
slot->host->ocr_avail_sd = MMC_VDD_32_33 | MMC_VDD_33_34 |
MMC_VDD_29_30 | MMC_VDD_30_31 |
MMC_VDD_165_195; /* allow 1.8V */
slot->host->ocr_avail_mmc = MMC_VDD_32_33 | MMC_VDD_33_34 |
MMC_VDD_29_30 | MMC_VDD_30_31; /* no 1.8V for MMC */
}
/* /*
* The secondary interface requires a bit set to get the * The secondary interface requires a bit set to get the
* interrupts. * interrupts.
*/ */
if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC) if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD)
jmicron_enable_mmc(slot->host, 1); jmicron_enable_mmc(slot->host, 1);
return 0; return 0;
...@@ -373,7 +389,8 @@ static void jmicron_remove_slot(struct sdhci_pci_slot *slot, int dead) ...@@ -373,7 +389,8 @@ static void jmicron_remove_slot(struct sdhci_pci_slot *slot, int dead)
if (dead) if (dead)
return; return;
if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC) if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD)
jmicron_enable_mmc(slot->host, 0); jmicron_enable_mmc(slot->host, 0);
} }
...@@ -381,7 +398,8 @@ static int jmicron_suspend(struct sdhci_pci_chip *chip, pm_message_t state) ...@@ -381,7 +398,8 @@ static int jmicron_suspend(struct sdhci_pci_chip *chip, pm_message_t state)
{ {
int i; int i;
if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC) { if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
for (i = 0;i < chip->num_slots;i++) for (i = 0;i < chip->num_slots;i++)
jmicron_enable_mmc(chip->slots[i]->host, 0); jmicron_enable_mmc(chip->slots[i]->host, 0);
} }
...@@ -393,7 +411,8 @@ static int jmicron_resume(struct sdhci_pci_chip *chip) ...@@ -393,7 +411,8 @@ static int jmicron_resume(struct sdhci_pci_chip *chip)
{ {
int ret, i; int ret, i;
if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC) { if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
for (i = 0;i < chip->num_slots;i++) for (i = 0;i < chip->num_slots;i++)
jmicron_enable_mmc(chip->slots[i]->host, 1); jmicron_enable_mmc(chip->slots[i]->host, 1);
} }
...@@ -581,6 +600,22 @@ static const struct pci_device_id pci_ids[] __devinitdata = { ...@@ -581,6 +600,22 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.driver_data = (kernel_ulong_t)&sdhci_jmicron, .driver_data = (kernel_ulong_t)&sdhci_jmicron,
}, },
{
.vendor = PCI_VENDOR_ID_JMICRON,
.device = PCI_DEVICE_ID_JMICRON_JMB388_SD,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_jmicron,
},
{
.vendor = PCI_VENDOR_ID_JMICRON,
.device = PCI_DEVICE_ID_JMICRON_JMB388_ESD,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_jmicron,
},
{ {
.vendor = PCI_VENDOR_ID_SYSKONNECT, .vendor = PCI_VENDOR_ID_SYSKONNECT,
.device = 0x8000, .device = 0x8000,
......
...@@ -1739,7 +1739,7 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host); ...@@ -1739,7 +1739,7 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host);
int sdhci_add_host(struct sdhci_host *host) int sdhci_add_host(struct sdhci_host *host)
{ {
struct mmc_host *mmc; struct mmc_host *mmc;
unsigned int caps; unsigned int caps, ocr_avail;
int ret; int ret;
WARN_ON(host == NULL); WARN_ON(host == NULL);
...@@ -1893,13 +1893,26 @@ int sdhci_add_host(struct sdhci_host *host) ...@@ -1893,13 +1893,26 @@ int sdhci_add_host(struct sdhci_host *host)
mmc_card_is_removable(mmc)) mmc_card_is_removable(mmc))
mmc->caps |= MMC_CAP_NEEDS_POLL; mmc->caps |= MMC_CAP_NEEDS_POLL;
mmc->ocr_avail = 0; ocr_avail = 0;
if (caps & SDHCI_CAN_VDD_330) if (caps & SDHCI_CAN_VDD_330)
mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34; ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
if (caps & SDHCI_CAN_VDD_300) if (caps & SDHCI_CAN_VDD_300)
mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31; ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
if (caps & SDHCI_CAN_VDD_180) if (caps & SDHCI_CAN_VDD_180)
mmc->ocr_avail |= MMC_VDD_165_195; ocr_avail |= MMC_VDD_165_195;
mmc->ocr_avail = ocr_avail;
mmc->ocr_avail_sdio = ocr_avail;
if (host->ocr_avail_sdio)
mmc->ocr_avail_sdio &= host->ocr_avail_sdio;
mmc->ocr_avail_sd = ocr_avail;
if (host->ocr_avail_sd)
mmc->ocr_avail_sd &= host->ocr_avail_sd;
else /* normal SD controllers don't support 1.8V */
mmc->ocr_avail_sd &= ~MMC_VDD_165_195;
mmc->ocr_avail_mmc = ocr_avail;
if (host->ocr_avail_mmc)
mmc->ocr_avail_mmc &= host->ocr_avail_mmc;
if (mmc->ocr_avail == 0) { if (mmc->ocr_avail == 0) {
printk(KERN_ERR "%s: Hardware doesn't report any " printk(KERN_ERR "%s: Hardware doesn't report any "
......
...@@ -131,6 +131,9 @@ struct mmc_host { ...@@ -131,6 +131,9 @@ struct mmc_host {
unsigned int f_max; unsigned int f_max;
unsigned int f_init; unsigned int f_init;
u32 ocr_avail; u32 ocr_avail;
u32 ocr_avail_sdio; /* SDIO-specific OCR */
u32 ocr_avail_sd; /* SD-specific OCR */
u32 ocr_avail_mmc; /* MMC-specific OCR */
struct notifier_block pm_notify; struct notifier_block pm_notify;
#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */ #define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */
......
...@@ -139,6 +139,10 @@ struct sdhci_host { ...@@ -139,6 +139,10 @@ struct sdhci_host {
unsigned int caps; /* Alternative capabilities */ unsigned int caps; /* Alternative capabilities */
unsigned int ocr_avail_sdio; /* OCR bit masks */
unsigned int ocr_avail_sd;
unsigned int ocr_avail_mmc;
unsigned long private[0] ____cacheline_aligned; unsigned long private[0] ____cacheline_aligned;
}; };
#endif /* __SDHCI_H */ #endif /* __SDHCI_H */
...@@ -2368,6 +2368,8 @@ ...@@ -2368,6 +2368,8 @@
#define PCI_DEVICE_ID_JMICRON_JMB38X_SD 0x2381 #define PCI_DEVICE_ID_JMICRON_JMB38X_SD 0x2381
#define PCI_DEVICE_ID_JMICRON_JMB38X_MMC 0x2382 #define PCI_DEVICE_ID_JMICRON_JMB38X_MMC 0x2382
#define PCI_DEVICE_ID_JMICRON_JMB38X_MS 0x2383 #define PCI_DEVICE_ID_JMICRON_JMB38X_MS 0x2383
#define PCI_DEVICE_ID_JMICRON_JMB388_SD 0x2391
#define PCI_DEVICE_ID_JMICRON_JMB388_ESD 0x2392
#define PCI_VENDOR_ID_KORENIX 0x1982 #define PCI_VENDOR_ID_KORENIX 0x1982
#define PCI_DEVICE_ID_KORENIX_JETCARDF0 0x1600 #define PCI_DEVICE_ID_KORENIX_JETCARDF0 0x1600
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册