|
@@ -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;
|