net: Add a flow_cache_flush_deferred function
[pandora-kernel.git] / drivers / mmc / host / sdhci-esdhc-imx.c
index 4dc0028..4b976f0 100644 (file)
 /* VENDOR SPEC register */
 #define SDHCI_VENDOR_SPEC              0xC0
 #define  SDHCI_VENDOR_SPEC_SDIO_QUIRK  0x00000002
+#define SDHCI_WTMK_LVL                 0x44
+#define SDHCI_MIX_CTRL                 0x48
+
+/*
+ * There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC:
+ * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design,
+ * but bit28 is used as the INT DMA ERR in fsl eSDHC design.
+ * Define this macro DMA error INT for fsl eSDHC
+ */
+#define SDHCI_INT_VENDOR_SPEC_DMA_ERR  0x10000000
 
 /*
  * The CMDTYPE of the CMD register (offset 0xE) should be set to
@@ -51,6 +61,7 @@ enum imx_esdhc_type {
        IMX35_ESDHC,
        IMX51_ESDHC,
        IMX53_ESDHC,
+       IMX6Q_USDHC,
 };
 
 struct pltfm_imx_data {
@@ -73,6 +84,9 @@ static struct platform_device_id imx_esdhc_devtype[] = {
        }, {
                .name = "sdhci-esdhc-imx53",
                .driver_data = IMX53_ESDHC,
+       }, {
+               .name = "sdhci-usdhc-imx6q",
+               .driver_data = IMX6Q_USDHC,
        }, {
                /* sentinel */
        }
@@ -84,6 +98,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = {
        { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], },
        { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], },
        { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], },
+       { .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
@@ -108,6 +123,11 @@ static inline int is_imx53_esdhc(struct pltfm_imx_data *data)
        return data->devtype == IMX53_ESDHC;
 }
 
+static inline int is_imx6q_usdhc(struct pltfm_imx_data *data)
+{
+       return data->devtype == IMX6Q_USDHC;
+}
+
 static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
 {
        void __iomem *base = host->ioaddr + (reg & ~0x3);
@@ -135,6 +155,27 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
                        val |= SDHCI_CARD_PRESENT;
        }
 
+       if (unlikely(reg == SDHCI_CAPABILITIES)) {
+               /* In FSL esdhc IC module, only bit20 is used to indicate the
+                * ADMA2 capability of esdhc, but this bit is messed up on
+                * some SOCs (e.g. on MX25, MX35 this bit is set, but they
+                * don't actually support ADMA2). So set the BROKEN_ADMA
+                * uirk on MX25/35 platforms.
+                */
+
+               if (val & SDHCI_CAN_DO_ADMA1) {
+                       val &= ~SDHCI_CAN_DO_ADMA1;
+                       val |= SDHCI_CAN_DO_ADMA2;
+               }
+       }
+
+       if (unlikely(reg == SDHCI_INT_STATUS)) {
+               if (val & SDHCI_INT_VENDOR_SPEC_DMA_ERR) {
+                       val &= ~SDHCI_INT_VENDOR_SPEC_DMA_ERR;
+                       val |= SDHCI_INT_ADMA_ERROR;
+               }
+       }
+
        return val;
 }
 
@@ -179,13 +220,28 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
                        writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
        }
 
+       if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) {
+               if (val & SDHCI_INT_ADMA_ERROR) {
+                       val &= ~SDHCI_INT_ADMA_ERROR;
+                       val |= SDHCI_INT_VENDOR_SPEC_DMA_ERR;
+               }
+       }
+
        writel(val, host->ioaddr + reg);
 }
 
 static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
 {
-       if (unlikely(reg == SDHCI_HOST_VERSION))
-               reg ^= 2;
+       if (unlikely(reg == SDHCI_HOST_VERSION)) {
+               u16 val = readw(host->ioaddr + (reg ^ 2));
+               /*
+                * uSDHC supports SDHCI v3.0, but it's encoded as value
+                * 0x3 in host controller version register, which violates
+                * SDHCI_SPEC_300 definition.  Work it around here.
+                */
+               if ((val & SDHCI_SPEC_VER_MASK) == 3)
+                       return --val;
+       }
 
        return readw(host->ioaddr + reg);
 }
@@ -216,8 +272,17 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
                if ((host->cmd->opcode == MMC_STOP_TRANSMISSION)
                        && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
                        val |= SDHCI_CMD_ABORTCMD;
-               writel(val << 16 | imx_data->scratchpad,
-                       host->ioaddr + SDHCI_TRANSFER_MODE);
+
+               if (is_imx6q_usdhc(imx_data)) {
+                       u32 m = readl(host->ioaddr + SDHCI_MIX_CTRL);
+                       m = imx_data->scratchpad | (m & 0xffff0000);
+                       writel(m, host->ioaddr + SDHCI_MIX_CTRL);
+                       writel(val << 16,
+                              host->ioaddr + SDHCI_TRANSFER_MODE);
+               } else {
+                       writel(val << 16 | imx_data->scratchpad,
+                              host->ioaddr + SDHCI_TRANSFER_MODE);
+               }
                return;
        case SDHCI_BLOCK_SIZE:
                val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
@@ -311,9 +376,10 @@ static struct sdhci_ops sdhci_esdhc_ops = {
 };
 
 static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
-       .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
+       .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT
+                       | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
+                       | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC
                        | SDHCI_QUIRK_BROKEN_CARD_DETECTION,
-       /* ADMA has issues. Might be fixable */
        .ops = &sdhci_esdhc_ops,
 };
 
@@ -405,11 +471,19 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
 
        if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data))
                /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
-               host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
+               host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK
+                       | SDHCI_QUIRK_BROKEN_ADMA;
 
        if (is_imx53_esdhc(imx_data))
                imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
 
+       /*
+        * The imx6q ROM code will change the default watermark level setting
+        * to something insane.  Change it back here.
+        */
+       if (is_imx6q_usdhc(imx_data))
+               writel(0x08100810, host->ioaddr + SDHCI_WTMK_LVL);
+
        boarddata = &imx_data->boarddata;
        if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
                if (!host->mmc->parent->platform_data) {