Hi!
These are the patches Andres made sent upstream:
http://www.gossamer-threads.com/lists/linux/kernel/936294
http://www.gossamer-threads.com/lists/linux/kernel/937056
If they don't make it to 2.6.26, I'd suggest having them applied in the
package (unless Andres has any objections, of course).
--
Robert Millan
GPLv2 I know my rights; I want my phone call!
DRM What good is a phone call… if you are unable to speak?
(as seen on /.)
http://www.gossamer-threads.com/lists/linux/kernel/936294
From 23a46157c15badacb23332abb8f489a515d7733f Mon Sep 17 00:00:00 2001
From: Andres Salomon [EMAIL PROTECTED]
Date: Sat, 21 Jun 2008 19:27:10 -0400
Subject: [PATCH] [OLPC] sdhci: add quirk for the Marvell CaFe's vdd/powerup issue
The Marvell CaFe chip's SD implementation chokes during card insertion
if one attempts to set the voltage and power up in the same
SDHCI_POWER_CONTROL register write. This adds a quirk that does
that particular dance in two steps.
It also adds an entry to pci_ids.h for the CaFe chip's SD device.
Signed-off-by: Andres Salomon [EMAIL PROTECTED]
---
drivers/mmc/host/sdhci.c | 18 ++
include/linux/pci_ids.h |1 +
2 files changed, 19 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 07c2048..5b74c8c 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -55,6 +55,8 @@ static unsigned int debug_quirks = 0;
#define SDHCI_QUIRK_32BIT_DMA_SIZE (17)
/* Controller needs to be reset after each request to stay stable */
#define SDHCI_QUIRK_RESET_AFTER_REQUEST (18)
+/* Controller needs voltage and power writes to happen separately */
+#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (19)
static const struct pci_device_id pci_ids[] __devinitdata = {
{
@@ -128,6 +130,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
},
{
+ .vendor = PCI_VENDOR_ID_MARVELL,
+ .device = PCI_DEVICE_ID_MARVELL_CAFE_SD,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data= SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER,
+ },
+
+ {
.vendor = PCI_VENDOR_ID_JMICRON,
.device = PCI_DEVICE_ID_JMICRON_JMB38X_SD,
.subvendor = PCI_ANY_ID,
@@ -774,6 +784,14 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
BUG();
}
+ /*
+ * At least the 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-chip-quirks SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER))
+ writeb(pwr ~SDHCI_POWER_ON,
+host-ioaddr + SDHCI_POWER_CONTROL);
+
writeb(pwr, host-ioaddr + SDHCI_POWER_CONTROL);
out:
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index eafc9d6..6595382 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1520,6 +1520,7 @@
#define PCI_DEVICE_ID_MARVELL_GT64260 0x6430
#define PCI_DEVICE_ID_MARVELL_MV64360 0x6460
#define PCI_DEVICE_ID_MARVELL_MV64460 0x6480
+#define PCI_DEVICE_ID_MARVELL_CAFE_SD 0x4101
#define PCI_VENDOR_ID_V3 0x11b0
#define PCI_DEVICE_ID_V3_V960 0x0001
--
1.5.5.3
http://www.gossamer-threads.com/lists/linux/kernel/937056
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 5b74c8c..2b3f06a 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -57,6 +57,8 @@ static unsigned int debug_quirks = 0;
#define SDHCI_QUIRK_RESET_AFTER_REQUEST (18)
/* Controller needs voltage and power writes to happen separately */
#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (19)
+/* Controller has an off-by-one issue with timeout value */
+#define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL (110)
static const struct pci_device_id pci_ids[] __devinitdata = {
{
@@ -134,7 +136,8 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.device = PCI_DEVICE_ID_MARVELL_CAFE_SD,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data= SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER,
+ .driver_data= SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
+ SDHCI_QUIRK_INCR_TIMEOUT_CONTROL,
},
{
@@ -479,6 +482,13 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
break;
}
+ /*
+ * Compensate for an off-by-one error in the CaFe hardware; otherwise,
+ * a too-small count gives us interrupt timeouts.
+ */
+ if ((host-chip-quirks SDHCI_QUIRK_INCR_TIMEOUT_CONTROL))
+ count++;
+
if (count = 0xF) {
printk(KERN_WARNING %s: Too large timeout requested!\n,
mmc_hostname(host-mmc));