Merge tag 'mac80211-next-for-john-2014-11-04' of git://git.kernel.org/pub/scm/linux...
[cascardo/linux.git] / drivers / mmc / host / mmci.c
index e4d4707..43af791 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/sizes.h>
 
 #include "mmci.h"
+#include "mmci_qcom_dml.h"
 
 #define DRIVER_NAME "mmci-pl18x"
 
@@ -60,12 +61,13 @@ static unsigned int fmax = 515633;
  * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
  *               is asserted (likewise for RX)
  * @data_cmd_enable: enable value for data commands.
- * @sdio: variant supports SDIO
+ * @st_sdio: enable ST specific SDIO logic
  * @st_clkdiv: true if using a ST-specific clock divider algorithm
  * @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
  * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
  * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
  *                  register
+ * @datactrl_mask_sdio: SDIO enable mask in datactrl register
  * @pwrreg_powerup: power up value for MMCIPOWER register
  * @f_max: maximum clk frequency supported by the controller.
  * @signal_direction: input/out direction of bus signals can be indicated
@@ -74,6 +76,7 @@ static unsigned int fmax = 515633;
  * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
  * @explicit_mclk_control: enable explicit mclk control in driver.
  * @qcom_fifo: enables qcom specific fifo pio read logic.
+ * @qcom_dml: enables qcom specific dma glue for dma transfers.
  * @reversed_irq_handling: handle data irq before cmd irq.
  */
 struct variant_data {
@@ -86,7 +89,8 @@ struct variant_data {
        unsigned int            fifohalfsize;
        unsigned int            data_cmd_enable;
        unsigned int            datactrl_mask_ddrmode;
-       bool                    sdio;
+       unsigned int            datactrl_mask_sdio;
+       bool                    st_sdio;
        bool                    st_clkdiv;
        bool                    blksz_datactrl16;
        bool                    blksz_datactrl4;
@@ -98,6 +102,7 @@ struct variant_data {
        bool                    pwrreg_nopower;
        bool                    explicit_mclk_control;
        bool                    qcom_fifo;
+       bool                    qcom_dml;
        bool                    reversed_irq_handling;
 };
 
@@ -133,7 +138,8 @@ static struct variant_data variant_u300 = {
        .clkreg_enable          = MCI_ST_U300_HWFCEN,
        .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
        .datalength_bits        = 16,
-       .sdio                   = true,
+       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
+       .st_sdio                        = true,
        .pwrreg_powerup         = MCI_PWR_ON,
        .f_max                  = 100000000,
        .signal_direction       = true,
@@ -146,7 +152,8 @@ static struct variant_data variant_nomadik = {
        .fifohalfsize           = 8 * 4,
        .clkreg                 = MCI_CLK_ENABLE,
        .datalength_bits        = 24,
-       .sdio                   = true,
+       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
+       .st_sdio                = true,
        .st_clkdiv              = true,
        .pwrreg_powerup         = MCI_PWR_ON,
        .f_max                  = 100000000,
@@ -163,7 +170,8 @@ static struct variant_data variant_ux500 = {
        .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
        .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
        .datalength_bits        = 24,
-       .sdio                   = true,
+       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
+       .st_sdio                = true,
        .st_clkdiv              = true,
        .pwrreg_powerup         = MCI_PWR_ON,
        .f_max                  = 100000000,
@@ -182,7 +190,8 @@ static struct variant_data variant_ux500v2 = {
        .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
        .datactrl_mask_ddrmode  = MCI_ST_DPSM_DDRMODE,
        .datalength_bits        = 24,
-       .sdio                   = true,
+       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
+       .st_sdio                = true,
        .st_clkdiv              = true,
        .blksz_datactrl16       = true,
        .pwrreg_powerup         = MCI_PWR_ON,
@@ -208,6 +217,7 @@ static struct variant_data variant_qcom = {
        .f_max                  = 208000000,
        .explicit_mclk_control  = true,
        .qcom_fifo              = true,
+       .qcom_dml               = true,
 };
 
 static int mmci_card_busy(struct mmc_host *mmc)
@@ -421,6 +431,7 @@ static void mmci_dma_setup(struct mmci_host *host)
 {
        const char *rxname, *txname;
        dma_cap_mask_t mask;
+       struct variant_data *variant = host->variant;
 
        host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx");
        host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx");
@@ -471,6 +482,10 @@ static void mmci_dma_setup(struct mmci_host *host)
                if (max_seg_size < host->mmc->max_seg_size)
                        host->mmc->max_seg_size = max_seg_size;
        }
+
+       if (variant->qcom_dml && host->dma_rx_channel && host->dma_tx_channel)
+               if (dml_hw_init(host, host->mmc->parent->of_node))
+                       variant->qcom_dml = false;
 }
 
 /*
@@ -572,6 +587,7 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
        struct dma_async_tx_descriptor *desc;
        enum dma_data_direction buffer_dirn;
        int nr_sg;
+       unsigned long flags = DMA_CTRL_ACK;
 
        if (data->flags & MMC_DATA_READ) {
                conf.direction = DMA_DEV_TO_MEM;
@@ -596,9 +612,12 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
        if (nr_sg == 0)
                return -EINVAL;
 
+       if (host->variant->qcom_dml)
+               flags |= DMA_PREP_INTERRUPT;
+
        dmaengine_slave_config(chan, &conf);
        desc = dmaengine_prep_slave_sg(chan, data->sg, nr_sg,
-                                           conf.direction, DMA_CTRL_ACK);
+                                           conf.direction, flags);
        if (!desc)
                goto unmap_exit;
 
@@ -647,6 +666,9 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
        dmaengine_submit(host->dma_desc_current);
        dma_async_issue_pending(host->dma_current);
 
+       if (host->variant->qcom_dml)
+               dml_start_xfer(host, data);
+
        datactrl |= MCI_DPSM_DMAENABLE;
 
        /* Trigger the DMA transfer */
@@ -792,32 +814,26 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
        if (data->flags & MMC_DATA_READ)
                datactrl |= MCI_DPSM_DIRECTION;
 
-       /* The ST Micro variants has a special bit to enable SDIO */
-       if (variant->sdio && host->mmc->card)
-               if (mmc_card_sdio(host->mmc->card)) {
-                       /*
-                        * The ST Micro variants has a special bit
-                        * to enable SDIO.
-                        */
-                       u32 clk;
+       if (host->mmc->card && mmc_card_sdio(host->mmc->card)) {
+               u32 clk;
 
-                       datactrl |= MCI_ST_DPSM_SDIOEN;
+               datactrl |= variant->datactrl_mask_sdio;
 
-                       /*
-                        * The ST Micro variant for SDIO small write transfers
-                        * needs to have clock H/W flow control disabled,
-                        * otherwise the transfer will not start. The threshold
-                        * depends on the rate of MCLK.
-                        */
-                       if (data->flags & MMC_DATA_WRITE &&
-                           (host->size < 8 ||
-                            (host->size <= 8 && host->mclk > 50000000)))
-                               clk = host->clk_reg & ~variant->clkreg_enable;
-                       else
-                               clk = host->clk_reg | variant->clkreg_enable;
+               /*
+                * The ST Micro variant for SDIO small write transfers
+                * needs to have clock H/W flow control disabled,
+                * otherwise the transfer will not start. The threshold
+                * depends on the rate of MCLK.
+                */
+               if (variant->st_sdio && data->flags & MMC_DATA_WRITE &&
+                   (host->size < 8 ||
+                    (host->size <= 8 && host->mclk > 50000000)))
+                       clk = host->clk_reg & ~variant->clkreg_enable;
+               else
+                       clk = host->clk_reg | variant->clkreg_enable;
 
-                       mmci_write_clkreg(host, clk);
-               }
+               mmci_write_clkreg(host, clk);
+       }
 
        if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
            host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
@@ -1658,16 +1674,35 @@ static int mmci_probe(struct amba_device *dev,
        writel(0, host->base + MMCIMASK1);
        writel(0xfff, host->base + MMCICLEAR);
 
-       /* If DT, cd/wp gpios must be supplied through it. */
-       if (!np && gpio_is_valid(plat->gpio_cd)) {
-               ret = mmc_gpio_request_cd(mmc, plat->gpio_cd, 0);
-               if (ret)
-                       goto clk_disable;
-       }
-       if (!np && gpio_is_valid(plat->gpio_wp)) {
-               ret = mmc_gpio_request_ro(mmc, plat->gpio_wp);
-               if (ret)
-                       goto clk_disable;
+       /*
+        * If:
+        * - not using DT but using a descriptor table, or
+        * - using a table of descriptors ALONGSIDE DT, or
+        * look up these descriptors named "cd" and "wp" right here, fail
+        * silently of these do not exist and proceed to try platform data
+        */
+       if (!np) {
+               ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0, NULL);
+               if (ret < 0) {
+                       if (ret == -EPROBE_DEFER)
+                               goto clk_disable;
+                       else if (gpio_is_valid(plat->gpio_cd)) {
+                               ret = mmc_gpio_request_cd(mmc, plat->gpio_cd, 0);
+                               if (ret)
+                                       goto clk_disable;
+                       }
+               }
+
+               ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0, NULL);
+               if (ret < 0) {
+                       if (ret == -EPROBE_DEFER)
+                               goto clk_disable;
+                       else if (gpio_is_valid(plat->gpio_wp)) {
+                               ret = mmc_gpio_request_ro(mmc, plat->gpio_wp);
+                               if (ret)
+                                       goto clk_disable;
+                       }
+               }
        }
 
        ret = devm_request_irq(&dev->dev, dev->irq[0], mmci_irq, IRQF_SHARED,