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 (1<<7) /* Controller needs to be reset after each request to stay stable */ #define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<8) +/* Controller needs voltage and power writes to happen separately */ +#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<9) 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 (1<<8) /* Controller needs voltage and power writes to happen separately */ #define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<9) +/* Controller has an off-by-one issue with timeout value */ +#define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL (1<<10) 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));