]> git.karo-electronics.de Git - linux-beck.git/commitdiff
mmc: sdhci: Factor out tuning helper functions
authorAdrian Hunter <adrian.hunter@intel.com>
Fri, 2 Dec 2016 13:59:23 +0000 (15:59 +0200)
committerUlf Hansson <ulf.hansson@linaro.org>
Mon, 5 Dec 2016 13:16:23 +0000 (14:16 +0100)
Factor out some functions to tidy up the code in sdhci_execute_tuning.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/sdhci.c

index b841d0a57af19a164240bb7f71978075c65666da..a6f8e164b3fdb46818af475e7be1fa4322b8fcdf 100644 (file)
@@ -1952,6 +1952,122 @@ static int sdhci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
        return 0;
 }
 
+static void sdhci_start_tuning(struct sdhci_host *host)
+{
+       u16 ctrl;
+
+       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       ctrl |= SDHCI_CTRL_EXEC_TUNING;
+       if (host->quirks2 & SDHCI_QUIRK2_TUNING_WORK_AROUND)
+               ctrl |= SDHCI_CTRL_TUNED_CLK;
+       sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+       /*
+        * As per the Host Controller spec v3.00, tuning command
+        * generates Buffer Read Ready interrupt, so enable that.
+        *
+        * Note: The spec clearly says that when tuning sequence
+        * is being performed, the controller does not generate
+        * interrupts other than Buffer Read Ready interrupt. But
+        * to make sure we don't hit a controller bug, we _only_
+        * enable Buffer Read Ready interrupt here.
+        */
+       sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
+       sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);
+}
+
+static void sdhci_end_tuning(struct sdhci_host *host)
+{
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+}
+
+static void sdhci_reset_tuning(struct sdhci_host *host)
+{
+       u16 ctrl;
+
+       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       ctrl &= ~SDHCI_CTRL_TUNED_CLK;
+       ctrl &= ~SDHCI_CTRL_EXEC_TUNING;
+       sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+}
+
+static void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode,
+                              unsigned long flags)
+{
+       sdhci_reset_tuning(host);
+
+       sdhci_do_reset(host, SDHCI_RESET_CMD);
+       sdhci_do_reset(host, SDHCI_RESET_DATA);
+
+       sdhci_end_tuning(host);
+
+       spin_unlock_irqrestore(&host->lock, flags);
+       mmc_abort_tuning(host->mmc, opcode);
+       spin_lock_irqsave(&host->lock, flags);
+}
+
+/*
+ * We use sdhci_send_tuning() because mmc_send_tuning() is not a good fit. SDHCI
+ * tuning command does not have a data payload (or rather the hardware does it
+ * automatically) so mmc_send_tuning() will return -EIO. Also the tuning command
+ * interrupt setup is different to other commands and there is no timeout
+ * interrupt so special handling is needed.
+ */
+static void sdhci_send_tuning(struct sdhci_host *host, u32 opcode,
+                             unsigned long flags)
+{
+       struct mmc_host *mmc = host->mmc;
+       struct mmc_command cmd = {0};
+       struct mmc_request mrq = {NULL};
+
+       cmd.opcode = opcode;
+       cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+       cmd.mrq = &mrq;
+
+       mrq.cmd = &cmd;
+       /*
+        * In response to CMD19, the card sends 64 bytes of tuning
+        * block to the Host Controller. So we set the block size
+        * to 64 here.
+        */
+       if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) {
+               if (mmc->ios.bus_width == MMC_BUS_WIDTH_8)
+                       sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128),
+                                    SDHCI_BLOCK_SIZE);
+               else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4)
+                       sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
+                                    SDHCI_BLOCK_SIZE);
+       } else {
+               sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
+                            SDHCI_BLOCK_SIZE);
+       }
+
+       /*
+        * The tuning block is sent by the card to the host controller.
+        * So we set the TRNS_READ bit in the Transfer Mode register.
+        * This also takes care of setting DMA Enable and Multi Block
+        * Select in the same register to 0.
+        */
+       sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
+
+       sdhci_send_command(host, &cmd);
+
+       host->cmd = NULL;
+
+       sdhci_del_timer(host, &mrq);
+
+       host->tuning_done = 0;
+
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       /* Wait for Buffer Read Ready interrupt */
+       wait_event_timeout(host->buf_ready_int, (host->tuning_done == 1),
+                          msecs_to_jiffies(50));
+
+       spin_lock_irqsave(&host->lock, flags);
+}
+
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
        struct sdhci_host *host = mmc_priv(mmc);
@@ -2011,105 +2127,24 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                return err;
        }
 
-       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-       ctrl |= SDHCI_CTRL_EXEC_TUNING;
-       if (host->quirks2 & SDHCI_QUIRK2_TUNING_WORK_AROUND)
-               ctrl |= SDHCI_CTRL_TUNED_CLK;
-       sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-
-       /*
-        * As per the Host Controller spec v3.00, tuning command
-        * generates Buffer Read Ready interrupt, so enable that.
-        *
-        * Note: The spec clearly says that when tuning sequence
-        * is being performed, the controller does not generate
-        * interrupts other than Buffer Read Ready interrupt. But
-        * to make sure we don't hit a controller bug, we _only_
-        * enable Buffer Read Ready interrupt here.
-        */
-       sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
-       sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);
+       sdhci_start_tuning(host);
 
        /*
         * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
         * of loops reaches 40 times.
         */
        do {
-               struct mmc_command cmd = {0};
-               struct mmc_request mrq = {NULL};
-
-               cmd.opcode = opcode;
-               cmd.arg = 0;
-               cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-               cmd.retries = 0;
-               cmd.data = NULL;
-               cmd.mrq = &mrq;
-               cmd.error = 0;
-
                if (tuning_loop_counter-- == 0)
                        break;
 
-               mrq.cmd = &cmd;
-
-               /*
-                * In response to CMD19, the card sends 64 bytes of tuning
-                * block to the Host Controller. So we set the block size
-                * to 64 here.
-                */
-               if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) {
-                       if (mmc->ios.bus_width == MMC_BUS_WIDTH_8)
-                               sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128),
-                                            SDHCI_BLOCK_SIZE);
-                       else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4)
-                               sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
-                                            SDHCI_BLOCK_SIZE);
-               } else {
-                       sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
-                                    SDHCI_BLOCK_SIZE);
-               }
-
-               /*
-                * The tuning block is sent by the card to the host controller.
-                * So we set the TRNS_READ bit in the Transfer Mode register.
-                * This also takes care of setting DMA Enable and Multi Block
-                * Select in the same register to 0.
-                */
-               sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
-
-               sdhci_send_command(host, &cmd);
-
-               host->cmd = NULL;
-               sdhci_del_timer(host, &mrq);
-
-               spin_unlock_irqrestore(&host->lock, flags);
-               /* Wait for Buffer Read Ready interrupt */
-               wait_event_timeout(host->buf_ready_int,
-                                       (host->tuning_done == 1),
-                                       msecs_to_jiffies(50));
-               spin_lock_irqsave(&host->lock, flags);
+               sdhci_send_tuning(host, opcode, flags);
 
                if (!host->tuning_done) {
                        pr_info(DRIVER_NAME ": Timeout waiting for Buffer Read Ready interrupt during tuning procedure, falling back to fixed sampling clock\n");
-                       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-                       ctrl &= ~SDHCI_CTRL_TUNED_CLK;
-                       ctrl &= ~SDHCI_CTRL_EXEC_TUNING;
-                       sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-
-                       sdhci_do_reset(host, SDHCI_RESET_CMD);
-                       sdhci_do_reset(host, SDHCI_RESET_DATA);
-
-                       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
-                       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
-
-                       spin_unlock_irqrestore(&host->lock, flags);
-                       mmc_abort_tuning(mmc, opcode);
-                       spin_lock_irqsave(&host->lock, flags);
-
+                       sdhci_abort_tuning(host, opcode, flags);
                        goto out;
                }
 
-               host->tuning_done = 0;
-
                ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 
                /* eMMC spec does not require a delay between tuning cycles */
@@ -2121,18 +2156,15 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
         * The Host Driver has exhausted the maximum number of loops allowed,
         * so use fixed sampling frequency.
         */
-       if (tuning_loop_counter < 0) {
-               ctrl &= ~SDHCI_CTRL_TUNED_CLK;
-               ctrl &= ~SDHCI_CTRL_EXEC_TUNING;
-               sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-       }
-       if (!(ctrl & SDHCI_CTRL_TUNED_CLK))
+       if (tuning_loop_counter < 0)
+               sdhci_reset_tuning(host);
+
+       if (tuning_loop_counter < 0 || !(ctrl & SDHCI_CTRL_TUNED_CLK))
                pr_info(DRIVER_NAME ": Tuning procedure failed, falling back to fixed sampling clock\n");
 out:
        host->mmc->retune_period = tuning_count;
 
-       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
-       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+       sdhci_end_tuning(host);
 out_unlock:
        spin_unlock_irqrestore(&host->lock, flags);
        return err;