mmc: sdhci: Factor out tuning helper functions
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>
This commit is contained in:
parent
d0c3ab5910
commit
da4bc4f285
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user