Add two new quirks:
authorStephen Hurd <shurd@broadcom.com>
Thu, 23 Aug 2012 19:00:14 +0000 (12:00 -0700)
committerGerrit <chrome-bot@google.com>
Fri, 24 Aug 2012 06:26:33 +0000 (23:26 -0700)
SDHCI_QUIRK2_BROKEN_UHS:
    Disables all UHS modes.

SDHCI_QUIRK2_BROADCOM_REGISTERS:
    Bit twiddles some Broadcom-specific registers and supresses an error
    about the 64k bar0.

Add PCI fixes structs:
One for the chip itself with the required quirks in general (lightly tested)
and one that is Parrot specific which adds the new SDHCI_QUIRK2_BROKEN_UHS
quirk, disables ADMA mode, and adds a delay after power.

BUG=chrome-os-partner:12366
TEST=Excercise IO on SD/SDHC/MMC cards on a Parrot device.

Signed-off-by: Stephen Hurd <shurd@broadcom.com>
Change-Id: I278a19084b2dd9ddf3aedf2aaf14a9962080610d
Reviewed-on: https://gerrit.chromium.org/gerrit/31240
Commit-Ready: Stephen Hurd <shurd@broadcom.com>
Reviewed-by: Stephen Hurd <shurd@broadcom.com>
Tested-by: Stephen Hurd <shurd@broadcom.com>
Commit-Ready: Grant Grundler <grundler@chromium.org>
Reviewed-by: Grant Grundler <grundler@chromium.org>
Reviewed-by: Dave Parker <dparker@chromium.org>
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci.c
include/linux/mmc/sdhci.h

index 69ef0be..d4248bb 100644 (file)
@@ -160,6 +160,28 @@ static const struct sdhci_pci_fixes sdhci_cafe = {
                          SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
 };
 
+#define BRCM_SDHCI_QUIRKS ( \
+       SDHCI_QUIRK_32BIT_DMA_ADDR | \
+       SDHCI_QUIRK_32BIT_DMA_SIZE | \
+       SDHCI_QUIRK_32BIT_ADMA_SIZE | \
+       SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | \
+       SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 | \
+       0)
+#define BRCM_SDHCI_QUIRKS2 ( \
+       SDHCI_QUIRK2_BROADCOM_REGISTERS | \
+       0)
+
+static const struct sdhci_pci_fixes sdhci_brcm = {
+       .quirks         = BRCM_SDHCI_QUIRKS,
+       .quirks2        = BRCM_SDHCI_QUIRKS2,
+};
+
+static const struct sdhci_pci_fixes sdhci_nouhs_brcm = {
+       .quirks         = BRCM_SDHCI_QUIRKS | SDHCI_QUIRK_DELAY_AFTER_POWER |
+                               SDHCI_QUIRK_BROKEN_ADMA,
+       .quirks2        = BRCM_SDHCI_QUIRKS2 | SDHCI_QUIRK2_BROKEN_UHS,
+};
+
 static int mrst_hc_probe_slot(struct sdhci_pci_slot *slot)
 {
        slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA;
@@ -893,6 +915,22 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
                .driver_data    = (kernel_ulong_t)&sdhci_o2,
        },
 
+       {
+               .vendor         = PCI_VENDOR_ID_BROADCOM,
+               .device         = 0x16bc,
+               .subvendor      = PCI_VENDOR_ID_AI,
+               .subdevice      = 0x0742,
+               .driver_data    = (kernel_ulong_t)&sdhci_nouhs_brcm,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_BROADCOM,
+               .device         = 0x16bc,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_brcm,
+       },
+
        {       /* Generic SD host controller */
                PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
        },
@@ -1195,7 +1233,9 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
                return ERR_PTR(-ENODEV);
        }
 
-       if (pci_resource_len(pdev, bar) != 0x100) {
+       if (pci_resource_len(pdev, bar) !=
+                   (chip->quirks2 & SDHCI_QUIRK2_BROADCOM_REGISTERS ?
+                   0x10000 : 0x100)) {
                dev_err(&pdev->dev, "Invalid iomem size. You may "
                        "experience problems.\n");
        }
index ccefdeb..a14a5d7 100644 (file)
@@ -1085,6 +1085,23 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
                        return;
        }
 
+       if (host->quirks2 & SDHCI_QUIRK2_BROADCOM_REGISTERS) {
+               u32 tmp;
+
+               tmp = sdhci_readl(host, 0x198);
+               tmp &= ~0x3000;
+               sdhci_writel(host, tmp, 0x198);
+
+               tmp = sdhci_readl(host, 0x19c);
+               tmp &= ~(0x01a03f30);
+               tmp |= (0x00500000);
+
+               if ((sdhci_readw(host, SDHCI_HOST_CONTROL2) &
+                           SDHCI_CTRL_VDD_180) && (clock >= 200000000))
+                       tmp |= (1<<24);
+               sdhci_writel(host, tmp, 0x19c);
+       }
+
        sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
 
        if (clock == 0)
@@ -1444,9 +1461,13 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                        ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
                        if (ios->timing == MMC_TIMING_MMC_HS200)
                                ctrl_2 |= SDHCI_CTRL_HS_SDR200;
-                       else if (ios->timing == MMC_TIMING_UHS_SDR12)
+                       else if ((ios->timing == MMC_TIMING_UHS_SDR12) &&
+                                   /* Also is MMC_TIMING_LEGACY */
+                                   (host->mmc->caps & MMC_CAP_UHS_SDR12))
                                ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
-                       else if (ios->timing == MMC_TIMING_UHS_SDR25)
+                       else if ((ios->timing == MMC_TIMING_UHS_SDR25) &&
+                                   /* Also is MMC_TIMING_SD_HS */
+                                   (host->mmc->caps & MMC_CAP_UHS_SDR25))
                                ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
                        else if (ios->timing == MMC_TIMING_UHS_SDR50)
                                ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
@@ -2613,9 +2634,14 @@ int sdhci_add_host(struct sdhci_host *host)
 
        caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
                sdhci_readl(host, SDHCI_CAPABILITIES);
+       if (host->quirks2 & SDHCI_QUIRK2_BROKEN_UHS)
+               caps[0] &= ~(SDHCI_CAN_VDD_180);
 
        caps[1] = (host->version >= SDHCI_SPEC_300) ?
                sdhci_readl(host, SDHCI_CAPABILITIES_1) : 0;
+       if (host->quirks2 & SDHCI_QUIRK2_BROKEN_UHS)
+               caps[1] &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
+                           SDHCI_SUPPORT_DDR50 | SDHCI_USE_SDR50_TUNING);
 
        if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
                host->flags |= SDHCI_USE_SDMA;
index e9051e1..9338160 100644 (file)
@@ -91,6 +91,10 @@ struct sdhci_host {
        unsigned int quirks2;   /* More deviations from spec. */
 
 #define SDHCI_QUIRK2_HOST_OFF_CARD_ON                  (1<<0)
+/* UHS modes do not work */
+#define SDHCI_QUIRK2_BROKEN_UHS                                        (1<<1)
+/* Has additional Broadcom-specific registers */
+#define SDHCI_QUIRK2_BROADCOM_REGISTERS                        (1<<2)
 
        int irq;                /* Device IRQ */
        void __iomem *ioaddr;   /* Mapped address */