From 6882a8c071d609f4c088bee41e79572c7cfc1790 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sun, 14 Jun 2009 13:52:38 +0100 Subject: sdhci: Add better ADMA error reporting Update the ADMA error reporting to not only show the overall controller state but also to print the ADMA descriptor list. Signed-off-by: Ben Dooks Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 35789c6edc19..e54d6fba85e1 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1382,6 +1382,35 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) sdhci_finish_command(host); } +#ifdef DEBUG +static void sdhci_show_adma_error(struct sdhci_host *host) +{ + const char *name = mmc_hostname(host->mmc); + u8 *desc = host->adma_desc; + __le32 *dma; + __le16 *len; + u8 attr; + + sdhci_dumpregs(host); + + while (true) { + dma = (__le32 *)(desc + 4); + len = (__le16 *)(desc + 2); + attr = *desc; + + DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n", + name, desc, le32_to_cpu(*dma), le16_to_cpu(*len), attr); + + desc += 8; + + if (attr & 2) + break; + } +} +#else +static void sdhci_show_adma_error(struct sdhci_host *host) { } +#endif + static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) { BUG_ON(intmask == 0); @@ -1411,8 +1440,11 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) host->data->error = -ETIMEDOUT; else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT)) host->data->error = -EILSEQ; - else if (intmask & SDHCI_INT_ADMA_ERROR) + else if (intmask & SDHCI_INT_ADMA_ERROR) { + printk(KERN_ERR "%s: ADMA error\n", mmc_hostname(host->mmc)); + sdhci_show_adma_error(host); host->data->error = -EIO; + } if (host->data->error) sdhci_finish_data(host); -- cgit v1.2.3 From 1388eefd5a5e6aaa3cb04070bfc2b944c1d24b82 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sun, 14 Jun 2009 12:40:53 +0100 Subject: sdhci: Add SDHCI_QUIRK_NO_MULTIBLOCK quirk Add quirk to show the controller cannot do multi-block IO. This is mainly for the Samsung SDHCI controller that currently cannot manage to do multi-block PIO without timing out. Signed-off-by: Ben Dooks Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci-s3c.c | 3 +++ drivers/mmc/host/sdhci.c | 2 +- drivers/mmc/host/sdhci.h | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 19246fe3d3e2..50997d2a63e7 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -329,6 +329,9 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) * support as well. */ host->quirks |= SDHCI_QUIRK_BROKEN_DMA; + /* PIO currently has problems with multi-block IO */ + host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; + #endif /* CONFIG_MMC_SDHCI_S3C_DMA */ /* It seems we do not get an DATA transfer complete on non-busy diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index e54d6fba85e1..3856669aa7e8 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1834,7 +1834,7 @@ int sdhci_add_host(struct sdhci_host *host) /* * Maximum block count. */ - mmc->max_blk_count = 65535; + mmc->max_blk_count = (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535; /* * Init tasklets. diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 2de08349c3ca..84d149096f0e 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -226,6 +226,8 @@ struct sdhci_host { #define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET (1<<19) /* Controller has to be forced to use block size of 2048 bytes */ #define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20) +/* Controller cannot do multi-block transfers */ +#define SDHCI_QUIRK_NO_MULTIBLOCK (1<<21) int irq; /* Device IRQ */ void __iomem * ioaddr; /* Mapped address */ -- cgit v1.2.3 From 5fe23c7f51def59f66bc6aeee988ef1a467a2c8c Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 18 Jun 2009 00:14:08 +0400 Subject: sdhci: Add support for hosts that are only capable of 1-bit transfers Some hosts (hardware configurations, or particular SD/MMC slots) may not support 4-bit bus. For example, on MPC8569E-MDS boards we can switch between serial (1-bit only) and nibble (4-bit) modes, thought we have to disable more peripherals to work in 4-bit mode. Along with some small core changes, this patch modifies sdhci-of driver, so that now it looks for "sdhci,1-bit-only" property in the device-tree, and if specified we enable a proper quirk. Signed-off-by: Anton Vorontsov Acked-by: Grant Likely Signed-off-by: Pierre Ossman --- Documentation/powerpc/dts-bindings/fsl/esdhc.txt | 2 ++ drivers/mmc/host/sdhci-of.c | 3 +++ drivers/mmc/host/sdhci.c | 5 ++++- drivers/mmc/host/sdhci.h | 2 ++ 4 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/Documentation/powerpc/dts-bindings/fsl/esdhc.txt b/Documentation/powerpc/dts-bindings/fsl/esdhc.txt index 5093ddf900da..3ed3797b5086 100644 --- a/Documentation/powerpc/dts-bindings/fsl/esdhc.txt +++ b/Documentation/powerpc/dts-bindings/fsl/esdhc.txt @@ -10,6 +10,8 @@ Required properties: - interrupts : should contain eSDHC interrupt. - interrupt-parent : interrupt source phandle. - clock-frequency : specifies eSDHC base clock frequency. + - sdhci,1-bit-only : (optional) specifies that a controller can + only handle 1-bit data transfers. Example: diff --git a/drivers/mmc/host/sdhci-of.c b/drivers/mmc/host/sdhci-of.c index 128c614d11aa..d79fa55c3b89 100644 --- a/drivers/mmc/host/sdhci-of.c +++ b/drivers/mmc/host/sdhci-of.c @@ -250,6 +250,9 @@ static int __devinit sdhci_of_probe(struct of_device *ofdev, host->ops = &sdhci_of_data->ops; } + if (of_get_property(np, "sdhci,1-bit-only", NULL)) + host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; + clk = of_get_property(np, "clock-frequency", &size); if (clk && size == sizeof(*clk) && *clk) of_host->clock = *clk; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 3856669aa7e8..c7586739be1e 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1761,7 +1761,10 @@ int sdhci_add_host(struct sdhci_host *host) mmc->ops = &sdhci_ops; mmc->f_min = host->max_clk / 256; mmc->f_max = host->max_clk; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; + mmc->caps = MMC_CAP_SDIO_IRQ; + + if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA)) + mmc->caps |= MMC_CAP_4_BIT_DATA; if (caps & SDHCI_CAN_DO_HISPD) mmc->caps |= MMC_CAP_SD_HIGHSPEED; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 84d149096f0e..5d37dd94b53f 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -228,6 +228,8 @@ struct sdhci_host { #define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20) /* Controller cannot do multi-block transfers */ #define SDHCI_QUIRK_NO_MULTIBLOCK (1<<21) +/* Controller can only handle 1-bit data transfers */ +#define SDHCI_QUIRK_FORCE_1_BIT_DATA (1<<22) int irq; /* Device IRQ */ void __iomem * ioaddr; /* Mapped address */ -- cgit v1.2.3 From 557b06971b1f05cbadec2f376a305ee1954e9b0d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 18 Jun 2009 16:53:38 +0200 Subject: sdhci: Specific quirk vor VIA SDHCI controller in VX855ES The SDHCI controller found in the VX855ES requires 10ms delay between applying power and applying clock. This issue has been discovered and documented by the OLPC XO1.5 team. Signed-off-by: Harald Welte Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci-pci.c | 20 ++++++++++++++++++++ drivers/mmc/host/sdhci.c | 7 +++++++ drivers/mmc/host/sdhci.h | 2 ++ 3 files changed, 29 insertions(+) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 65be27995d5c..2f15cc17d887 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -284,6 +284,18 @@ static const struct sdhci_pci_fixes sdhci_jmicron = { .resume = jmicron_resume, }; +static int via_probe(struct sdhci_pci_chip *chip) +{ + if (chip->pdev->revision == 0x10) + chip->quirks |= SDHCI_QUIRK_DELAY_AFTER_POWER; + + return 0; +} + +static const struct sdhci_pci_fixes sdhci_via = { + .probe = via_probe, +}; + static const struct pci_device_id pci_ids[] __devinitdata = { { .vendor = PCI_VENDOR_ID_RICOH, @@ -349,6 +361,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = { .driver_data = (kernel_ulong_t)&sdhci_jmicron, }, + { + .vendor = PCI_VENDOR_ID_VIA, + .device = 0x95d0, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_via, + }, + { /* Generic SD host controller */ PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) }, diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c7586739be1e..f4066fdc8906 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1057,6 +1057,13 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) pwr |= SDHCI_POWER_ON; sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); + + /* + * Some controllers need an extra 10ms delay of 10ms before they + * can apply clock after applying power + */ + if ((host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)) + mdelay(10); } /*****************************************************************************\ diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 5d37dd94b53f..831ddf7dcb49 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -230,6 +230,8 @@ struct sdhci_host { #define SDHCI_QUIRK_NO_MULTIBLOCK (1<<21) /* Controller can only handle 1-bit data transfers */ #define SDHCI_QUIRK_FORCE_1_BIT_DATA (1<<22) +/* Controller needs 10ms delay between applying power and clock */ +#define SDHCI_QUIRK_DELAY_AFTER_POWER (1<<23) int irq; /* Device IRQ */ void __iomem * ioaddr; /* Mapped address */ -- cgit v1.2.3 From 11a2f1b78a43d0c2bd026d79b952742c7588f529 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 21 Jun 2009 20:59:33 +0200 Subject: sdhci: remove needless double parenthesis Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index f4066fdc8906..6779b4ecab18 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -584,7 +584,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data) * longer to time out, but that's much better than having a too-short * timeout value. */ - if ((host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)) + if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) return 0xE; /* timeout in us */ @@ -1051,7 +1051,7 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) * At least the Marvell CaFe chip gets confused if we set the voltage * and set turn on power at the same time, so set the voltage first. */ - if ((host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)) + if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER) sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); pwr |= SDHCI_POWER_ON; @@ -1062,7 +1062,7 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) * Some controllers need an extra 10ms delay of 10ms before they * can apply clock after applying power */ - if ((host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)) + if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER) mdelay(10); } -- cgit v1.2.3 From a9e58f25734e153b8c6516d904e2398fb8b0b23d Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Wed, 29 Jul 2009 15:04:16 -0700 Subject: sdhci: get rid of "frequency too high" flood when using eSDHC Since commit 8dfd0374be84793360db7fff2e635d2cd3bbcb21 ("MMC core: limit minimum initialization frequency to 400kHz") MMC core checks for minimum frequency, and that causes following messages flood when using eSDHC controllers: ... mmc0: Minimum clock frequency too high for identification mode mmc0: Minimum clock frequency too high for identification mode ... The warnings are legitimate, since if we'd use 133 MHz clocks for standard SDHCI controllers, we'd not able to scale frequency down to 400 kHz. But eSDHC controllers have a non-standard SD clock management, so we can divide clock by 256 * 16, not just 256. This patch introduces get_min_clock() callback for sdhci core and implements it for sdhci-of driver, and thus fixes the issue. Signed-off-by: Anton Vorontsov Cc: Matt Fleming Cc: Ian Molton Cc: "Roberto A. Foglietta" Cc: Pierre Ossman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/sdhci-of.c | 8 ++++++++ drivers/mmc/host/sdhci.c | 5 ++++- drivers/mmc/host/sdhci.h | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci-of.c b/drivers/mmc/host/sdhci-of.c index d79fa55c3b89..908844327db0 100644 --- a/drivers/mmc/host/sdhci-of.c +++ b/drivers/mmc/host/sdhci-of.c @@ -158,6 +158,13 @@ static unsigned int esdhc_get_max_clock(struct sdhci_host *host) return of_host->clock; } +static unsigned int esdhc_get_min_clock(struct sdhci_host *host) +{ + struct sdhci_of_host *of_host = sdhci_priv(host); + + return of_host->clock / 256 / 16; +} + static unsigned int esdhc_get_timeout_clock(struct sdhci_host *host) { struct sdhci_of_host *of_host = sdhci_priv(host); @@ -184,6 +191,7 @@ static struct sdhci_of_data sdhci_esdhc = { .set_clock = esdhc_set_clock, .enable_dma = esdhc_enable_dma, .get_max_clock = esdhc_get_max_clock, + .get_min_clock = esdhc_get_min_clock, .get_timeout_clock = esdhc_get_timeout_clock, }, }; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 6779b4ecab18..62041c7e9246 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1766,7 +1766,10 @@ int sdhci_add_host(struct sdhci_host *host) * Set host parameters. */ mmc->ops = &sdhci_ops; - mmc->f_min = host->max_clk / 256; + if (host->ops->get_min_clock) + mmc->f_min = host->ops->get_min_clock(host); + else + mmc->f_min = host->max_clk / 256; mmc->f_max = host->max_clk; mmc->caps = MMC_CAP_SDIO_IRQ; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 831ddf7dcb49..c77e9ff30223 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -302,6 +302,7 @@ struct sdhci_ops { int (*enable_dma)(struct sdhci_host *host); unsigned int (*get_max_clock)(struct sdhci_host *host); + unsigned int (*get_min_clock)(struct sdhci_host *host); unsigned int (*get_timeout_clock)(struct sdhci_host *host); }; -- cgit v1.2.3 From da60a91d012bcb10bc5bcd86d585c4281742832c Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 18 Jun 2009 09:33:32 +0200 Subject: sdhci: use SG_MITER_TO_SG/SG_MITER_FROM_SG so the page will be flushed on unmap on ARCH which need it. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 62041c7e9246..fc96f8cb9c0b 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -773,8 +773,14 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) } if (!(host->flags & SDHCI_REQ_USE_DMA)) { - sg_miter_start(&host->sg_miter, - data->sg, data->sg_len, SG_MITER_ATOMIC); + int flags; + + flags = SG_MITER_ATOMIC; + if (host->data->flags & MMC_DATA_READ) + flags |= SG_MITER_TO_SG; + else + flags |= SG_MITER_FROM_SG; + sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); host->blocks = data->blocks; } -- cgit v1.2.3