|
@@ -49,7 +49,7 @@ static void sdhci_finish_data(struct sdhci_host *);
|
|
|
|
|
|
static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
|
|
|
static void sdhci_finish_command(struct sdhci_host *);
|
|
|
-static int sdhci_execute_tuning(struct mmc_host *mmc);
|
|
|
+static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
|
|
|
static void sdhci_tuning_timer(unsigned long data);
|
|
|
|
|
|
#ifdef CONFIG_PM_RUNTIME
|
|
@@ -1014,7 +1014,8 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
|
|
|
flags |= SDHCI_CMD_INDEX;
|
|
|
|
|
|
/* CMD19 is special in that the Data Present Select should be set */
|
|
|
- if (cmd->data || (cmd->opcode == MMC_SEND_TUNING_BLOCK))
|
|
|
+ if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK ||
|
|
|
+ cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
|
|
|
flags |= SDHCI_CMD_DATA;
|
|
|
|
|
|
sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
|
|
@@ -1287,7 +1288,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
|
|
if ((host->flags & SDHCI_NEEDS_RETUNING) &&
|
|
|
!(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) {
|
|
|
spin_unlock_irqrestore(&host->lock, flags);
|
|
|
- sdhci_execute_tuning(mmc);
|
|
|
+ sdhci_execute_tuning(mmc, mrq->cmd->opcode);
|
|
|
spin_lock_irqsave(&host->lock, flags);
|
|
|
|
|
|
/* Restore original mmc_request structure */
|
|
@@ -1382,7 +1383,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
|
|
|
unsigned int clock;
|
|
|
|
|
|
/* In case of UHS-I modes, set High Speed Enable */
|
|
|
- if ((ios->timing == MMC_TIMING_UHS_SDR50) ||
|
|
|
+ if ((ios->timing == MMC_TIMING_MMC_HS200) ||
|
|
|
+ (ios->timing == MMC_TIMING_UHS_SDR50) ||
|
|
|
(ios->timing == MMC_TIMING_UHS_SDR104) ||
|
|
|
(ios->timing == MMC_TIMING_UHS_DDR50) ||
|
|
|
(ios->timing == MMC_TIMING_UHS_SDR25))
|
|
@@ -1435,7 +1437,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
|
|
|
ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
|
|
|
/* Select Bus Speed Mode for host */
|
|
|
ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
|
|
|
- if (ios->timing == MMC_TIMING_UHS_SDR12)
|
|
|
+ if (ios->timing == MMC_TIMING_MMC_HS200)
|
|
|
+ ctrl_2 |= SDHCI_CTRL_HS_SDR200;
|
|
|
+ else if (ios->timing == MMC_TIMING_UHS_SDR12)
|
|
|
ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
|
|
|
else if (ios->timing == MMC_TIMING_UHS_SDR25)
|
|
|
ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
|
|
@@ -1682,7 +1686,7 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-static int sdhci_execute_tuning(struct mmc_host *mmc)
|
|
|
+static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
|
|
{
|
|
|
struct sdhci_host *host;
|
|
|
u16 ctrl;
|
|
@@ -1690,6 +1694,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc)
|
|
|
int tuning_loop_counter = MAX_TUNING_LOOP;
|
|
|
unsigned long timeout;
|
|
|
int err = 0;
|
|
|
+ bool requires_tuning_nonuhs = false;
|
|
|
|
|
|
host = mmc_priv(mmc);
|
|
|
|
|
@@ -1700,13 +1705,19 @@ static int sdhci_execute_tuning(struct mmc_host *mmc)
|
|
|
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
|
|
|
|
|
|
/*
|
|
|
- * Host Controller needs tuning only in case of SDR104 mode
|
|
|
- * and for SDR50 mode when Use Tuning for SDR50 is set in
|
|
|
+ * The Host Controller needs tuning only in case of SDR104 mode
|
|
|
+ * and for SDR50 mode when Use Tuning for SDR50 is set in the
|
|
|
* Capabilities register.
|
|
|
+ * If the Host Controller supports the HS200 mode then the
|
|
|
+ * tuning function has to be executed.
|
|
|
*/
|
|
|
+ if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
|
|
|
+ (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
|
|
|
+ host->flags & SDHCI_HS200_NEEDS_TUNING))
|
|
|
+ requires_tuning_nonuhs = true;
|
|
|
+
|
|
|
if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) ||
|
|
|
- (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
|
|
|
- (host->flags & SDHCI_SDR50_NEEDS_TUNING)))
|
|
|
+ requires_tuning_nonuhs)
|
|
|
ctrl |= SDHCI_CTRL_EXEC_TUNING;
|
|
|
else {
|
|
|
spin_unlock(&host->lock);
|
|
@@ -1742,7 +1753,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc)
|
|
|
if (!tuning_loop_counter && !timeout)
|
|
|
break;
|
|
|
|
|
|
- cmd.opcode = MMC_SEND_TUNING_BLOCK;
|
|
|
+ cmd.opcode = opcode;
|
|
|
cmd.arg = 0;
|
|
|
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
|
|
cmd.retries = 0;
|
|
@@ -1757,7 +1768,17 @@ static int sdhci_execute_tuning(struct mmc_host *mmc)
|
|
|
* block to the Host Controller. So we set the block size
|
|
|
* to 64 here.
|
|
|
*/
|
|
|
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE);
|
|
|
+ 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.
|
|
@@ -2140,12 +2161,14 @@ static void sdhci_show_adma_error(struct sdhci_host *host) { }
|
|
|
|
|
|
static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
|
|
|
{
|
|
|
+ u32 command;
|
|
|
BUG_ON(intmask == 0);
|
|
|
|
|
|
/* CMD19 generates _only_ Buffer Read Ready interrupt */
|
|
|
if (intmask & SDHCI_INT_DATA_AVAIL) {
|
|
|
- if (SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) ==
|
|
|
- MMC_SEND_TUNING_BLOCK) {
|
|
|
+ command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND));
|
|
|
+ if (command == MMC_SEND_TUNING_BLOCK ||
|
|
|
+ command == MMC_SEND_TUNING_BLOCK_HS200) {
|
|
|
host->tuning_done = 1;
|
|
|
wake_up(&host->buf_ready_int);
|
|
|
return;
|
|
@@ -2747,10 +2770,14 @@ int sdhci_add_host(struct sdhci_host *host)
|
|
|
if (caps[1] & SDHCI_SUPPORT_DDR50)
|
|
|
mmc->caps |= MMC_CAP_UHS_DDR50;
|
|
|
|
|
|
- /* Does the host needs tuning for SDR50? */
|
|
|
+ /* Does the host need tuning for SDR50? */
|
|
|
if (caps[1] & SDHCI_USE_SDR50_TUNING)
|
|
|
host->flags |= SDHCI_SDR50_NEEDS_TUNING;
|
|
|
|
|
|
+ /* Does the host need tuning for HS200? */
|
|
|
+ if (mmc->caps2 & MMC_CAP2_HS200)
|
|
|
+ host->flags |= SDHCI_HS200_NEEDS_TUNING;
|
|
|
+
|
|
|
/* Driver Type(s) (A, C, D) supported by the host */
|
|
|
if (caps[1] & SDHCI_DRIVER_TYPE_A)
|
|
|
mmc->caps |= MMC_CAP_DRIVER_TYPE_A;
|