mmc: mmci: Add sdio enable mask in variant data
[deliverable/linux.git] / drivers / mmc / host / mmci.c
index 6483c5cc67355ef0fed4bd2ca79ba2d7e15fa64a..370cd5ad111ce7fce35f9cfdc3340436d94c48a6 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/sizes.h>
 
 #include "mmci.h"
+#include "mmci_qcom_dml.h"
 
 #define DRIVER_NAME "mmci-pl18x"
 
@@ -66,6 +67,7 @@ static unsigned int fmax = 515633;
  * @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,8 @@ 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 {
        unsigned int            clkreg;
@@ -85,6 +89,7 @@ struct variant_data {
        unsigned int            fifohalfsize;
        unsigned int            data_cmd_enable;
        unsigned int            datactrl_mask_ddrmode;
+       unsigned int            datactrl_mask_sdio;
        bool                    sdio;
        bool                    st_clkdiv;
        bool                    blksz_datactrl16;
@@ -97,6 +102,8 @@ struct variant_data {
        bool                    pwrreg_nopower;
        bool                    explicit_mclk_control;
        bool                    qcom_fifo;
+       bool                    qcom_dml;
+       bool                    reversed_irq_handling;
 };
 
 static struct variant_data variant_arm = {
@@ -105,6 +112,7 @@ static struct variant_data variant_arm = {
        .datalength_bits        = 16,
        .pwrreg_powerup         = MCI_PWR_UP,
        .f_max                  = 100000000,
+       .reversed_irq_handling  = true,
 };
 
 static struct variant_data variant_arm_extended_fifo = {
@@ -130,6 +138,7 @@ static struct variant_data variant_u300 = {
        .clkreg_enable          = MCI_ST_U300_HWFCEN,
        .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
        .datalength_bits        = 16,
+       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
        .sdio                   = true,
        .pwrreg_powerup         = MCI_PWR_ON,
        .f_max                  = 100000000,
@@ -143,6 +152,7 @@ static struct variant_data variant_nomadik = {
        .fifohalfsize           = 8 * 4,
        .clkreg                 = MCI_CLK_ENABLE,
        .datalength_bits        = 24,
+       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
        .sdio                   = true,
        .st_clkdiv              = true,
        .pwrreg_powerup         = MCI_PWR_ON,
@@ -160,6 +170,7 @@ 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,
+       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
        .sdio                   = true,
        .st_clkdiv              = true,
        .pwrreg_powerup         = MCI_PWR_ON,
@@ -179,6 +190,7 @@ 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,
+       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
        .sdio                   = true,
        .st_clkdiv              = true,
        .blksz_datactrl16       = true,
@@ -205,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)
@@ -418,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");
@@ -468,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;
 }
 
 /*
@@ -569,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;
@@ -593,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;
 
@@ -644,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 */
@@ -789,16 +814,10 @@ 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;
-
-                       datactrl |= MCI_ST_DPSM_SDIOEN;
+                       datactrl |= variant->datactrl_mask_sdio;
 
                        /*
                         * The ST Micro variant for SDIO small write transfers
@@ -888,6 +907,10 @@ static void
 mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
              unsigned int status)
 {
+       /* Make sure we have data to handle */
+       if (!data)
+               return;
+
        /* First check for errors */
        if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR|
                      MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
@@ -956,9 +979,17 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
             unsigned int status)
 {
        void __iomem *base = host->base;
-       bool sbc = (cmd == host->mrq->sbc);
-       bool busy_resp = host->variant->busy_detect &&
-                       (cmd->flags & MMC_RSP_BUSY);
+       bool sbc, busy_resp;
+
+       if (!cmd)
+               return;
+
+       sbc = (cmd == host->mrq->sbc);
+       busy_resp = host->variant->busy_detect && (cmd->flags & MMC_RSP_BUSY);
+
+       if (!((status|host->busy_status) & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|
+               MCI_CMDSENT|MCI_CMDRESPEND)))
+               return;
 
        /* Check if we need to wait for busy completion. */
        if (host->busy_status && (status & MCI_ST_CARDBUSY))
@@ -1205,9 +1236,6 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
        spin_lock(&host->lock);
 
        do {
-               struct mmc_command *cmd;
-               struct mmc_data *data;
-
                status = readl(host->base + MMCISTATUS);
 
                if (host->singleirq) {
@@ -1227,16 +1255,13 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
 
                dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status);
 
-               cmd = host->cmd;
-               if ((status|host->busy_status) & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|
-                       MCI_CMDSENT|MCI_CMDRESPEND) && cmd)
-                       mmci_cmd_irq(host, cmd, status);
-
-               data = host->data;
-               if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR|
-                             MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_DATAEND|
-                             MCI_DATABLOCKEND) && data)
-                       mmci_data_irq(host, data, status);
+               if (host->variant->reversed_irq_handling) {
+                       mmci_data_irq(host, host->data, status);
+                       mmci_cmd_irq(host, host->cmd, status);
+               } else {
+                       mmci_cmd_irq(host, host->cmd, status);
+                       mmci_data_irq(host, host->data, status);
+               }
 
                /* Don't poll for busy completion in irq context. */
                if (host->busy_status)
@@ -1649,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);
+               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);
+               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,
This page took 0.026653 seconds and 5 git commands to generate.