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;
.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)
},
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");
}
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)
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;
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;
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 */