diff mbox

[V5] mmc: core: HS200 mode support for eMMC 4.5

Message ID 1322643228-10320-1-git-send-email-girish.shivananjappa@linaro.org
State New
Headers show

Commit Message

Girish K S Nov. 30, 2011, 8:53 a.m. UTC
This patch adds the support of the HS200 bus speed for eMMC 4.5 devices.
The eMMC 4.5 devices have support for 200MHz bus speed.The mmc core and
host modules have been touched to add support for this module.

It is necessary to know the card type in the sdhci.c file to add support
for eMMC tuning function. So card.h file is included to import the card
data structure.

cc: Chris Ball <cjb@laptop.org>
Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
---
Changes in v5:
	Reduced the case statements for better code readability. Removed
	unused macro definitions. Modified the tuning function prototype
	and definition to support tuning for both SD and eMMC cards.
Changes in v4:
	Rebased onto chris-mmc/mmc-next branch. This patch is successfully 
	applied on commit with id de022ed3fdc14808299b2fa66dbb1ed5ab921912.
Changes in v3:
	In the previous commits of chris-mmc/mmc-next branch, the patch with
	commit id (c0f22a2c92e357e7cb3988b0b13034d70b7461f9) defines caps2 for
	more capabilities. This patch version deletes the member ext_caps(created
	in my earlier patch) from struct mmc_host and reuses already accepted
	caps2 member.
Changes in v2:
	Rebased to latest chris-mmc/mmc-next branch. Resolved indentation
	problems identified in review. This patch has to be applied before
	the patch released for modifying the printk messages.
Changes in v1:
	Case statements in switch that produce same result have
	been combined to reduce repeated assignments.
	patch recreated after rebase to chris balls mmc-next branch.

 drivers/mmc/core/bus.c    |    3 +-
 drivers/mmc/core/mmc.c    |   77 ++++++++++++++++++++++++++++++++++++++++----
 drivers/mmc/core/sd.c     |    3 +-
 drivers/mmc/core/sdio.c   |    4 ++-
 drivers/mmc/host/sdhci.c  |   38 +++++++++++++++++-----
 include/linux/mmc/card.h  |    3 ++
 include/linux/mmc/host.h  |   11 ++++++-
 include/linux/mmc/mmc.h   |   66 ++++++++++++++++++++++++++++++++++++++-
 include/linux/mmc/sdhci.h |    1 +
 9 files changed, 185 insertions(+), 21 deletions(-)

Comments

Subhash Jadavani Dec. 1, 2011, 10:03 a.m. UTC | #1
Hi Girish,

> -----Original Message-----
> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
> owner@vger.kernel.org] On Behalf Of Girish K S
> Sent: Wednesday, November 30, 2011 2:24 PM
> To: linux-mmc@vger.kernel.org
> Cc: patches@linaro.org; linux-samsung-soc@vger.kernel.org;
> subhashj@codeaurora.org; Girish K S; Chris Ball
> Subject: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
> 
> This patch adds the support of the HS200 bus speed for eMMC 4.5
> devices.
> The eMMC 4.5 devices have support for 200MHz bus speed.The mmc core and
> host modules have been touched to add support for this module.
> 
> It is necessary to know the card type in the sdhci.c file to add
> support
> for eMMC tuning function. So card.h file is included to import the card
> data structure.
> 
> cc: Chris Ball <cjb@laptop.org>
> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
> ---
> Changes in v5:
> 	Reduced the case statements for better code readability. Removed
> 	unused macro definitions. Modified the tuning function prototype
> 	and definition to support tuning for both SD and eMMC cards.
> Changes in v4:
> 	Rebased onto chris-mmc/mmc-next branch. This patch is
> successfully
> 	applied on commit with id
> de022ed3fdc14808299b2fa66dbb1ed5ab921912.
> Changes in v3:
> 	In the previous commits of chris-mmc/mmc-next branch, the patch
> with
> 	commit id (c0f22a2c92e357e7cb3988b0b13034d70b7461f9) defines
> caps2 for
> 	more capabilities. This patch version deletes the member
> ext_caps(created
> 	in my earlier patch) from struct mmc_host and reuses already
> accepted
> 	caps2 member.
> Changes in v2:
> 	Rebased to latest chris-mmc/mmc-next branch. Resolved indentation
> 	problems identified in review. This patch has to be applied
> before
> 	the patch released for modifying the printk messages.
> Changes in v1:
> 	Case statements in switch that produce same result have
> 	been combined to reduce repeated assignments.
> 	patch recreated after rebase to chris balls mmc-next branch.
> 
>  drivers/mmc/core/bus.c    |    3 +-
>  drivers/mmc/core/mmc.c    |   77
> ++++++++++++++++++++++++++++++++++++++++----
>  drivers/mmc/core/sd.c     |    3 +-
>  drivers/mmc/core/sdio.c   |    4 ++-
>  drivers/mmc/host/sdhci.c  |   38 +++++++++++++++++-----
>  include/linux/mmc/card.h  |    3 ++
>  include/linux/mmc/host.h  |   11 ++++++-
>  include/linux/mmc/mmc.h   |   66
> ++++++++++++++++++++++++++++++++++++++-
>  include/linux/mmc/sdhci.h |    1 +
>  9 files changed, 185 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> index 5639fdf..83c9f8d 100644
> --- a/drivers/mmc/core/bus.c
> +++ b/drivers/mmc/core/bus.c
> @@ -301,10 +301,11 @@ int mmc_add_card(struct mmc_card *card)
>  			mmc_card_ddr_mode(card) ? "DDR " : "",
>  			type);
>  	} else {
> -		printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
> +		pr_info("%s: new %s%s%s%s card at address %04x\n",
>  			mmc_hostname(card->host),
>  			mmc_card_uhs(card) ? "ultra high speed " :
>  			(mmc_card_highspeed(card) ? "high speed " : ""),
> +			(mmc_card_hs200(card) ? "HS200 " : ""),
>  			mmc_card_ddr_mode(card) ? "DDR " : "",
>  			type, card->rca);
>  	}
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index a1223bd..f4124d6 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -285,6 +285,27 @@ static int mmc_read_ext_csd(struct mmc_card *card,
> u8 *ext_csd)
>  	}
>  	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>  	switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
> +	case EXT_CSD_CARD_TYPE_SDR_ALL:
> +	case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
> +	case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
> +	case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
> +		card->ext_csd.hs_max_dtr = 200000000;
> +		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
> +		break;
> +	case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
> +	case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
> +	case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
> +	case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
> +		card->ext_csd.hs_max_dtr = 200000000;
> +		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
> +		break;
> +	case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
> +	case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
> +	case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
> +	case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
> +		card->ext_csd.hs_max_dtr = 200000000;
> +		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
> +		break;
>  	case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
>  	     EXT_CSD_CARD_TYPE_26:
>  		card->ext_csd.hs_max_dtr = 52000000;
> @@ -699,6 +720,7 @@ static int mmc_init_card(struct mmc_host *host, u32
> ocr,
>  {
>  	struct mmc_card *card;
>  	int err, ddr = 0;
> +	int hs_sdr = 0;
>  	u32 cid[4];
>  	unsigned int max_dtr;
>  	u32 rocr;
> @@ -894,11 +916,16 @@ static int mmc_init_card(struct mmc_host *host,
> u32 ocr,
>  	/*
>  	 * Activate high speed (if supported)
>  	 */
> -	if ((card->ext_csd.hs_max_dtr != 0) &&
> -		(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
> -		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> -				 EXT_CSD_HS_TIMING, 1,
> -				 card->ext_csd.generic_cmd6_time);
> +	if (card->ext_csd.hs_max_dtr != 0) {
> +		err = 0;
> +		if ((card->ext_csd.hs_max_dtr > 52000000) &&
> +		    (host->caps2 & MMC_CAP2_HS200))
> +			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +					 EXT_CSD_HS_TIMING, 2, 0);
> +		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
> +			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +					 EXT_CSD_HS_TIMING, 1, 0);
> +
>  		if (err && err != -EBADMSG)
>  			goto free_card;
> 
> @@ -907,7 +934,11 @@ static int mmc_init_card(struct mmc_host *host,
> u32 ocr,
>  			       mmc_hostname(card->host));
>  			err = 0;
>  		} else {
> -			mmc_card_set_highspeed(card);
> +			if ((card->ext_csd.hs_max_dtr > 52000000) &&
> +			    (host->caps2 & MMC_CAP2_HS200))
> +				mmc_card_set_hs200(card);
> +			else
> +				mmc_card_set_highspeed(card);
>  			mmc_set_timing(card->host, MMC_TIMING_MMC_HS);

MMC_TIMING_MMC_HS200 is defined but still not used.

So I guess it should be like this ::
 +			if ((card->ext_csd.hs_max_dtr > 52000000) &&
 +			    (host->caps2 & MMC_CAP2_HS200)) {
 +				mmc_card_set_hs200(card);
 +     			mmc_set_timing(card->host, MMC_TIMING_MMC_HS200)
 +			} else {
 +				mmc_card_set_highspeed(card);
 +				mmc_set_timing(card->host,
MMC_TIMING_MMC_HS)
 + 			}














>  		}
>  	}
> @@ -933,7 +964,7 @@ static int mmc_init_card(struct mmc_host *host, u32
> ocr,
>  	 */
>  	max_dtr = (unsigned int)-1;
> 
> -	if (mmc_card_highspeed(card)) {
> +	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
>  		if (max_dtr > card->ext_csd.hs_max_dtr)
>  			max_dtr = card->ext_csd.hs_max_dtr;
>  	} else if (max_dtr > card->csd.max_dtr) {
> @@ -959,6 +990,18 @@ static int mmc_init_card(struct mmc_host *host,
> u32 ocr,
>  	}
> 
>  	/*
> +	 * Indicate HS200 SDR mode (if supported).
> +	 */
> +	if (mmc_card_hs200(card)) {
> +		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V)
> +			&& (host->caps2 & MMC_CAP2_HS200_1_8V_SDR))
> +				hs_sdr = MMC_1_8V_SDR_MODE;
> +		else if ((card->ext_csd.card_type &
> EXT_CSD_CARD_TYPE_SDR_1_2V)
> +			&& (host->caps2 & MMC_CAP2_HS200_1_2V_SDR))
> +				hs_sdr = MMC_1_2V_SDR_MODE;
> +	}
> +
> +	/*
>  	 * Activate wide bus and DDR (if supported).
>  	 */
>  	if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
> @@ -998,6 +1041,17 @@ static int mmc_init_card(struct mmc_host *host,
> u32 ocr,
>  			if (!err) {
>  				mmc_set_bus_width(card->host, bus_width);
> 
> +				if ((host->caps2 & MMC_CAP2_HS200) &&
> +				    card->host->ops->execute_tuning)
> +					err = card->host->ops->	\
> +					      execute_tuning(card->host,
> +
MMC_SEND_TUNING_BLOCK_HS200);


execute_tuning should be done right after the timing is changed to HS200 and
clock rate is changed to 200Mhz. This is not the correct sequence to call
the execute_tuning().

> +
> +				if (err) {
> +					pr_warning("tuning execution
failed\n");
> +					continue;
> +				}
> +
>  				/*
>  				 * If controller can't handle bus width
test,
>  				 * compare ext_csd previously read in 1 bit
> mode
> @@ -1056,6 +1110,15 @@ static int mmc_init_card(struct mmc_host *host,
> u32 ocr,
>  			mmc_card_set_ddr_mode(card);
>  			mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
>  			mmc_set_bus_width(card->host, bus_width);
> +		} else if (hs_sdr) {
> +			if (hs_sdr == EXT_CSD_CARD_TYPE_SDR_1_2V) {
> +				err = mmc_set_signal_voltage(host,
> +					MMC_SIGNAL_VOLTAGE_120, 0);
> +				if (err)
> +					goto err;
> +			}
> +			mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> +			mmc_set_bus_width(card->host, bus_width);
>  		}
>  	}
> 
> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> index 1d5a3bd..c1d3ee3 100644
> --- a/drivers/mmc/core/sd.c
> +++ b/drivers/mmc/core/sd.c
> @@ -660,7 +660,8 @@ static int mmc_sd_init_uhs_card(struct mmc_card
> *card)
> 
>  	/* SPI mode doesn't define CMD19 */
>  	if (!mmc_host_is_spi(card->host) && card->host->ops-
> >execute_tuning)
> -		err = card->host->ops->execute_tuning(card->host);
> +		err = card->host->ops->execute_tuning(card->host,	\
> +
MMC_SEND_TUNING_BLOCK);
> 
>  out:
>  	kfree(status);
> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
> index 8c04f7f..8ef8817 100644
> --- a/drivers/mmc/core/sdio.c
> +++ b/drivers/mmc/core/sdio.c
> @@ -14,6 +14,7 @@
> 
>  #include <linux/mmc/host.h>
>  #include <linux/mmc/card.h>
> +#include <linux/mmc/mmc.h>
>  #include <linux/mmc/sdio.h>
>  #include <linux/mmc/sdio_func.h>
>  #include <linux/mmc/sdio_ids.h>
> @@ -556,7 +557,8 @@ static int mmc_sdio_init_uhs_card(struct mmc_card
> *card)
> 
>  	/* Initialize and start re-tuning timer */
>  	if (!mmc_host_is_spi(card->host) && card->host->ops-
> >execute_tuning)
> -		err = card->host->ops->execute_tuning(card->host);
> +		err = card->host->ops->execute_tuning(card->host,
> +
MMC_SEND_TUNING_BLOCK);
> 
>  out:
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index a7c2311..13d74bb 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -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
> @@ -1016,7 +1016,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 */
> @@ -1673,7 +1674,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;
> @@ -1694,10 +1695,13 @@ static int sdhci_execute_tuning(struct mmc_host
> *mmc)
>  	 * Host Controller needs tuning only in case of SDR104 mode
>  	 * and for SDR50 mode when Use Tuning for SDR50 is set in
>  	 * Capabilities register.
> +	 * If the Host Controller supports the HS200 mode then tuning
> +	 * function has to be executed.
>  	 */
>  	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)))
> +	    (host->flags & SDHCI_SDR50_NEEDS_TUNING)) ||
> +	    (host->flags & SDHCI_HS200_NEEDS_TUNING))
>  		ctrl |= SDHCI_CTRL_EXEC_TUNING;
>  	else {
>  		spin_unlock(&host->lock);
> @@ -1733,7 +1737,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;
> @@ -1748,7 +1752,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.
> @@ -2131,12 +2145,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;
> @@ -2741,6 +2757,10 @@ int sdhci_add_host(struct sdhci_host *host)
>  	if (caps[1] & SDHCI_USE_SDR50_TUNING)
>  		host->flags |= SDHCI_SDR50_NEEDS_TUNING;
> 
> +	/* Does the host needs 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;
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index 534974c..e76f649 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -209,6 +209,7 @@ struct mmc_card {
>  #define MMC_STATE_HIGHSPEED_DDR (1<<4)		/* card is in high
> speed mode */
>  #define MMC_STATE_ULTRAHIGHSPEED (1<<5)		/* card is in ultra
> high speed mode */
>  #define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
> +#define MMC_STATE_HIGHSPEED_200	(1<<7)	/* card is in HS200
> mode */
>  	unsigned int		quirks; 	/* card quirks */
>  #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0
> writes outside of the VS CCCR range */
>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func-
> >cur_blksize */
> @@ -365,6 +366,7 @@ static inline void __maybe_unused
> remove_quirk(struct mmc_card *card, int data)
>  #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
>  #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
>  #define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
> +#define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
>  #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
>  #define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
>  #define mmc_card_uhs(c)		((c)->state &
> MMC_STATE_ULTRAHIGHSPEED)
> @@ -374,6 +376,7 @@ static inline void __maybe_unused
> remove_quirk(struct mmc_card *card, int data)
>  #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
>  #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
>  #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
> +#define mmc_card_set_hs200(c)	((c)->state |=
> MMC_STATE_HIGHSPEED_200)
>  #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
>  #define mmc_card_set_ddr_mode(c) ((c)->state |=
> MMC_STATE_HIGHSPEED_DDR)
>  #define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 706f722..5eac57a 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -50,6 +50,7 @@ struct mmc_ios {
> 
>  #define MMC_TIMING_LEGACY	0
>  #define MMC_TIMING_MMC_HS	1
> +#define MMC_TIMING_MMC_HS200	2
>  #define MMC_TIMING_SD_HS	2
>  #define MMC_TIMING_UHS_SDR12	MMC_TIMING_LEGACY
>  #define MMC_TIMING_UHS_SDR25	MMC_TIMING_SD_HS
> @@ -60,6 +61,8 @@ struct mmc_ios {
>  #define MMC_SDR_MODE		0
>  #define MMC_1_2V_DDR_MODE	1
>  #define MMC_1_8V_DDR_MODE	2
> +#define MMC_1_2V_SDR_MODE	3
> +#define MMC_1_8V_SDR_MODE	4
> 
>  	unsigned char	signal_voltage;		/* signalling voltage
> (1.8V or 3.3V) */
> 
> @@ -148,7 +151,9 @@ struct mmc_host_ops {
>  	void	(*init_card)(struct mmc_host *host, struct mmc_card *card);
> 
>  	int	(*start_signal_voltage_switch)(struct mmc_host *host,
> struct mmc_ios *ios);
> -	int	(*execute_tuning)(struct mmc_host *host);
> +
> +	/* The tuning command opcode value is different for SD and eMMC
> cards */
> +	int	(*execute_tuning)(struct mmc_host *host, u32 opcode);
>  	void	(*enable_preset_value)(struct mmc_host *host, bool enable);
>  	int	(*select_drive_strength)(unsigned int max_dtr, int
> host_drv, int card_drv);
>  	void	(*hw_reset)(struct mmc_host *host);
> @@ -242,6 +247,10 @@ struct mmc_host {
>  #define MMC_CAP2_CACHE_CTRL	(1 << 1)	/* Allow cache control */
>  #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)	/* Notify poweroff
> supported */
>  #define MMC_CAP2_NO_MULTI_READ	(1 << 3)	/* Multiblock reads
> don't work */
> +#define MMC_CAP2_HS200_1_8V_SDR	(1 << 4)	/* can support */
> +#define MMC_CAP2_HS200_1_2V_SDR	(1 << 5)	/* can support */
> +#define MMC_CAP2_HS200		(MMC_CAP2_HS200_1_8V_SDR | \
> +				 MMC_CAP2_HS200_1_2V_SDR)
> 
>  	mmc_pm_flag_t		pm_caps;	/* supported pm features */
>  	unsigned int        power_notify_type;
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 0e71356..7996272 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -51,6 +51,7 @@
>  #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1
> */
>  #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1
> */
>  #define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1
> */
> +#define MMC_SEND_TUNING_BLOCK_HS200	21	/* adtc R1  */
> 
>    /* class 3 */
>  #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1
> */
> @@ -333,13 +334,76 @@ struct _mmc_csd {
> 
>  #define EXT_CSD_CARD_TYPE_26	(1<<0)	/* Card can run at 26MHz */
>  #define EXT_CSD_CARD_TYPE_52	(1<<1)	/* Card can run at 52MHz */
> -#define EXT_CSD_CARD_TYPE_MASK	0xF	/* Mask out reserved bits */
> +#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz
> */
>  					     /* DDR mode @1.8V or 3V I/O */
>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz
> */
>  					     /* DDR mode @1.2V I/O */
>  #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
>  					| EXT_CSD_CARD_TYPE_DDR_1_2V)
> +#define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at
> 200MHz */
> +#define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at
> 200MHz */
> +						/* SDR mode @1.2V I/O */
> +
> +#define EXT_CSD_CARD_TYPE_SDR_200	(EXT_CSD_CARD_TYPE_SDR_1_8V	\
> +					| EXT_CSD_CARD_TYPE_SDR_1_2V)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_ALL	(EXT_CSD_CARD_TYPE_SDR_200	\
> +					| EXT_CSD_CARD_TYPE_52		\
> +					| EXT_CSD_CARD_TYPE_26)
> +
> +#define	EXT_CSD_CARD_TYPE_SDR_1_2V_ALL
> 	(EXT_CSD_CARD_TYPE_SDR_1_2V	\
> +					| EXT_CSD_CARD_TYPE_52		\
> +					| EXT_CSD_CARD_TYPE_26)
> +
> +#define	EXT_CSD_CARD_TYPE_SDR_1_8V_ALL
> 	(EXT_CSD_CARD_TYPE_SDR_1_8V	\
> +					| EXT_CSD_CARD_TYPE_52		\
> +					| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V
> 	(EXT_CSD_CARD_TYPE_SDR_1_2V  \
> +						| EXT_CSD_CARD_TYPE_DDR_1_8V
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V
> 	(EXT_CSD_CARD_TYPE_SDR_1_8V  \
> +						| EXT_CSD_CARD_TYPE_DDR_1_8V
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V
> 	(EXT_CSD_CARD_TYPE_SDR_1_2V  \
> +						| EXT_CSD_CARD_TYPE_DDR_1_2V
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V
> 	(EXT_CSD_CARD_TYPE_SDR_1_8V  \
> +						| EXT_CSD_CARD_TYPE_DDR_1_2V
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52
> 	(EXT_CSD_CARD_TYPE_SDR_1_2V  \
> +						| EXT_CSD_CARD_TYPE_DDR_52
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52
> 	(EXT_CSD_CARD_TYPE_SDR_1_8V  \
> +						| EXT_CSD_CARD_TYPE_DDR_52
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V
> 	(EXT_CSD_CARD_TYPE_SDR_200   \
> +						| EXT_CSD_CARD_TYPE_DDR_1_8V
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V
> 	(EXT_CSD_CARD_TYPE_SDR_200   \
> +						| EXT_CSD_CARD_TYPE_DDR_1_2V
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52	(EXT_CSD_CARD_TYPE_SDR_200
> \
> +						| EXT_CSD_CARD_TYPE_DDR_52
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> 
>  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
> diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
> index e4b6935..d9a2222 100644
> --- a/include/linux/mmc/sdhci.h
> +++ b/include/linux/mmc/sdhci.h
> @@ -121,6 +121,7 @@ struct sdhci_host {
>  #define SDHCI_AUTO_CMD23	(1<<7)	/* Auto CMD23 support */
>  #define SDHCI_PV_ENABLED	(1<<8)	/* Preset value enabled */
>  #define SDHCI_SDIO_IRQ_ENABLED	(1<<9)	/* SDIO irq enabled */
> +#define SDHCI_HS200_NEEDS_TUNING (1<<10)	/* HS200 needs tuning */
> 
>  	unsigned int version;	/* SDHCI spec. version */
> 
> --
> 1.7.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Girish K S Dec. 1, 2011, 10:28 a.m. UTC | #2
On 1 December 2011 15:33, Subhash Jadavani <subhashj@codeaurora.org> wrote:
> Hi Girish,
>
>> -----Original Message-----
>> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>> owner@vger.kernel.org] On Behalf Of Girish K S
>> Sent: Wednesday, November 30, 2011 2:24 PM
>> To: linux-mmc@vger.kernel.org
>> Cc: patches@linaro.org; linux-samsung-soc@vger.kernel.org;
>> subhashj@codeaurora.org; Girish K S; Chris Ball
>> Subject: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>>
>> This patch adds the support of the HS200 bus speed for eMMC 4.5
>> devices.
>> The eMMC 4.5 devices have support for 200MHz bus speed.The mmc core and
>> host modules have been touched to add support for this module.
>>
>> It is necessary to know the card type in the sdhci.c file to add
>> support
>> for eMMC tuning function. So card.h file is included to import the card
>> data structure.
>>
>> cc: Chris Ball <cjb@laptop.org>
>> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
>> ---
>> Changes in v5:
>>       Reduced the case statements for better code readability. Removed
>>       unused macro definitions. Modified the tuning function prototype
>>       and definition to support tuning for both SD and eMMC cards.
>> Changes in v4:
>>       Rebased onto chris-mmc/mmc-next branch. This patch is
>> successfully
>>       applied on commit with id
>> de022ed3fdc14808299b2fa66dbb1ed5ab921912.
>> Changes in v3:
>>       In the previous commits of chris-mmc/mmc-next branch, the patch
>> with
>>       commit id (c0f22a2c92e357e7cb3988b0b13034d70b7461f9) defines
>> caps2 for
>>       more capabilities. This patch version deletes the member
>> ext_caps(created
>>       in my earlier patch) from struct mmc_host and reuses already
>> accepted
>>       caps2 member.
>> Changes in v2:
>>       Rebased to latest chris-mmc/mmc-next branch. Resolved indentation
>>       problems identified in review. This patch has to be applied
>> before
>>       the patch released for modifying the printk messages.
>> Changes in v1:
>>       Case statements in switch that produce same result have
>>       been combined to reduce repeated assignments.
>>       patch recreated after rebase to chris balls mmc-next branch.
>>
>>  drivers/mmc/core/bus.c    |    3 +-
>>  drivers/mmc/core/mmc.c    |   77
>> ++++++++++++++++++++++++++++++++++++++++----
>>  drivers/mmc/core/sd.c     |    3 +-
>>  drivers/mmc/core/sdio.c   |    4 ++-
>>  drivers/mmc/host/sdhci.c  |   38 +++++++++++++++++-----
>>  include/linux/mmc/card.h  |    3 ++
>>  include/linux/mmc/host.h  |   11 ++++++-
>>  include/linux/mmc/mmc.h   |   66
>> ++++++++++++++++++++++++++++++++++++++-
>>  include/linux/mmc/sdhci.h |    1 +
>>  9 files changed, 185 insertions(+), 21 deletions(-)
>>
>> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> index 5639fdf..83c9f8d 100644
>> --- a/drivers/mmc/core/bus.c
>> +++ b/drivers/mmc/core/bus.c
>> @@ -301,10 +301,11 @@ int mmc_add_card(struct mmc_card *card)
>>                       mmc_card_ddr_mode(card) ? "DDR " : "",
>>                       type);
>>       } else {
>> -             printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
>> +             pr_info("%s: new %s%s%s%s card at address %04x\n",
>>                       mmc_hostname(card->host),
>>                       mmc_card_uhs(card) ? "ultra high speed " :
>>                       (mmc_card_highspeed(card) ? "high speed " : ""),
>> +                     (mmc_card_hs200(card) ? "HS200 " : ""),
>>                       mmc_card_ddr_mode(card) ? "DDR " : "",
>>                       type, card->rca);
>>       }
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index a1223bd..f4124d6 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -285,6 +285,27 @@ static int mmc_read_ext_csd(struct mmc_card *card,
>> u8 *ext_csd)
>>       }
>>       card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>>       switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
>> +     case EXT_CSD_CARD_TYPE_SDR_ALL:
>> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
>> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
>> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
>> +             card->ext_csd.hs_max_dtr = 200000000;
>> +             card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
>> +             break;
>> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
>> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
>> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
>> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
>> +             card->ext_csd.hs_max_dtr = 200000000;
>> +             card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
>> +             break;
>> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
>> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
>> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
>> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
>> +             card->ext_csd.hs_max_dtr = 200000000;
>> +             card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
>> +             break;
>>       case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
>>            EXT_CSD_CARD_TYPE_26:
>>               card->ext_csd.hs_max_dtr = 52000000;
>> @@ -699,6 +720,7 @@ static int mmc_init_card(struct mmc_host *host, u32
>> ocr,
>>  {
>>       struct mmc_card *card;
>>       int err, ddr = 0;
>> +     int hs_sdr = 0;
>>       u32 cid[4];
>>       unsigned int max_dtr;
>>       u32 rocr;
>> @@ -894,11 +916,16 @@ static int mmc_init_card(struct mmc_host *host,
>> u32 ocr,
>>       /*
>>        * Activate high speed (if supported)
>>        */
>> -     if ((card->ext_csd.hs_max_dtr != 0) &&
>> -             (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
>> -             err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> -                              EXT_CSD_HS_TIMING, 1,
>> -                              card->ext_csd.generic_cmd6_time);
>> +     if (card->ext_csd.hs_max_dtr != 0) {
>> +             err = 0;
>> +             if ((card->ext_csd.hs_max_dtr > 52000000) &&
>> +                 (host->caps2 & MMC_CAP2_HS200))
>> +                     err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +                                      EXT_CSD_HS_TIMING, 2, 0);
>> +             else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
>> +                     err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +                                      EXT_CSD_HS_TIMING, 1, 0);
>> +
>>               if (err && err != -EBADMSG)
>>                       goto free_card;
>>
>> @@ -907,7 +934,11 @@ static int mmc_init_card(struct mmc_host *host,
>> u32 ocr,
>>                              mmc_hostname(card->host));
>>                       err = 0;
>>               } else {
>> -                     mmc_card_set_highspeed(card);
>> +                     if ((card->ext_csd.hs_max_dtr > 52000000) &&
>> +                         (host->caps2 & MMC_CAP2_HS200))
>> +                             mmc_card_set_hs200(card);
>> +                     else
>> +                             mmc_card_set_highspeed(card);
>>                       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>
> MMC_TIMING_MMC_HS200 is defined but still not used.
>
> So I guess it should be like this ::
>  +                      if ((card->ext_csd.hs_max_dtr > 52000000) &&
>  +                          (host->caps2 & MMC_CAP2_HS200)) {
>  +                              mmc_card_set_hs200(card);
>  +                      mmc_set_timing(card->host, MMC_TIMING_MMC_HS200)
>  +                      } else {
>  +                              mmc_card_set_highspeed(card);
>  +                              mmc_set_timing(card->host,
> MMC_TIMING_MMC_HS)
>  +                      }
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>>               }
>>       }
>> @@ -933,7 +964,7 @@ static int mmc_init_card(struct mmc_host *host, u32
>> ocr,
>>        */
>>       max_dtr = (unsigned int)-1;
>>
>> -     if (mmc_card_highspeed(card)) {
>> +     if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
>>               if (max_dtr > card->ext_csd.hs_max_dtr)
>>                       max_dtr = card->ext_csd.hs_max_dtr;
>>       } else if (max_dtr > card->csd.max_dtr) {
>> @@ -959,6 +990,18 @@ static int mmc_init_card(struct mmc_host *host,
>> u32 ocr,
>>       }
>>
>>       /*
>> +      * Indicate HS200 SDR mode (if supported).
>> +      */
>> +     if (mmc_card_hs200(card)) {
>> +             if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V)
>> +                     && (host->caps2 & MMC_CAP2_HS200_1_8V_SDR))
>> +                             hs_sdr = MMC_1_8V_SDR_MODE;
>> +             else if ((card->ext_csd.card_type &
>> EXT_CSD_CARD_TYPE_SDR_1_2V)
>> +                     && (host->caps2 & MMC_CAP2_HS200_1_2V_SDR))
>> +                             hs_sdr = MMC_1_2V_SDR_MODE;
>> +     }
>> +
>> +     /*
>>        * Activate wide bus and DDR (if supported).
>>        */
>>       if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
>> @@ -998,6 +1041,17 @@ static int mmc_init_card(struct mmc_host *host,
>> u32 ocr,
>>                       if (!err) {
>>                               mmc_set_bus_width(card->host, bus_width);
>>
>> +                             if ((host->caps2 & MMC_CAP2_HS200) &&
>> +                                 card->host->ops->execute_tuning)
>> +                                     err = card->host->ops-> \
>> +                                           execute_tuning(card->host,
>> +
> MMC_SEND_TUNING_BLOCK_HS200);
>
>
> execute_tuning should be done right after the timing is changed to HS200 and
> clock rate is changed to 200Mhz. This is not the correct sequence to call
> the execute_tuning().
> As told earlier, It is mentioned in the spec that tuning should be executed after change of buswidth (mandatory). Also it mentions that "The host may invoke the HS200 tuning sequence, by sending CMD21 to the device". It means that
 after setting the HS200 mode, Changing to freq > 52Mhz and changing
the bus width tuning can be executed anytime to identify the sampling
point to read.(By anytime i mean before actual block read Operation).
Can you please point me to the place in the spec where it specifies
tuning should be done immediately after freq change (may be i missed
to read it).
>> +
>> +                             if (err) {
>> +                                     pr_warning("tuning execution
> failed\n");
>> +                                     continue;
>> +                             }
>> +
>>                               /*
>>                                * If controller can't handle bus width
> test,
>>                                * compare ext_csd previously read in 1 bit
>> mode
>> @@ -1056,6 +1110,15 @@ static int mmc_init_card(struct mmc_host *host,
>> u32 ocr,
>>                       mmc_card_set_ddr_mode(card);
>>                       mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
>>                       mmc_set_bus_width(card->host, bus_width);
>> +             } else if (hs_sdr) {
>> +                     if (hs_sdr == EXT_CSD_CARD_TYPE_SDR_1_2V) {
>> +                             err = mmc_set_signal_voltage(host,
>> +                                     MMC_SIGNAL_VOLTAGE_120, 0);
>> +                             if (err)
>> +                                     goto err;
>> +                     }
>> +                     mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> +                     mmc_set_bus_width(card->host, bus_width);
>>               }
>>       }
>>
>> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
>> index 1d5a3bd..c1d3ee3 100644
>> --- a/drivers/mmc/core/sd.c
>> +++ b/drivers/mmc/core/sd.c
>> @@ -660,7 +660,8 @@ static int mmc_sd_init_uhs_card(struct mmc_card
>> *card)
>>
>>       /* SPI mode doesn't define CMD19 */
>>       if (!mmc_host_is_spi(card->host) && card->host->ops-
>> >execute_tuning)
>> -             err = card->host->ops->execute_tuning(card->host);
>> +             err = card->host->ops->execute_tuning(card->host,       \
>> +
> MMC_SEND_TUNING_BLOCK);
>>
>>  out:
>>       kfree(status);
>> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
>> index 8c04f7f..8ef8817 100644
>> --- a/drivers/mmc/core/sdio.c
>> +++ b/drivers/mmc/core/sdio.c
>> @@ -14,6 +14,7 @@
>>
>>  #include <linux/mmc/host.h>
>>  #include <linux/mmc/card.h>
>> +#include <linux/mmc/mmc.h>
>>  #include <linux/mmc/sdio.h>
>>  #include <linux/mmc/sdio_func.h>
>>  #include <linux/mmc/sdio_ids.h>
>> @@ -556,7 +557,8 @@ static int mmc_sdio_init_uhs_card(struct mmc_card
>> *card)
>>
>>       /* Initialize and start re-tuning timer */
>>       if (!mmc_host_is_spi(card->host) && card->host->ops-
>> >execute_tuning)
>> -             err = card->host->ops->execute_tuning(card->host);
>> +             err = card->host->ops->execute_tuning(card->host,
>> +
> MMC_SEND_TUNING_BLOCK);
>>
>>  out:
>>
>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>> index a7c2311..13d74bb 100644
>> --- a/drivers/mmc/host/sdhci.c
>> +++ b/drivers/mmc/host/sdhci.c
>> @@ -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
>> @@ -1016,7 +1016,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 */
>> @@ -1673,7 +1674,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;
>> @@ -1694,10 +1695,13 @@ static int sdhci_execute_tuning(struct mmc_host
>> *mmc)
>>        * Host Controller needs tuning only in case of SDR104 mode
>>        * and for SDR50 mode when Use Tuning for SDR50 is set in
>>        * Capabilities register.
>> +      * If the Host Controller supports the HS200 mode then tuning
>> +      * function has to be executed.
>>        */
>>       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)))
>> +         (host->flags & SDHCI_SDR50_NEEDS_TUNING)) ||
>> +         (host->flags & SDHCI_HS200_NEEDS_TUNING))
>>               ctrl |= SDHCI_CTRL_EXEC_TUNING;
>>       else {
>>               spin_unlock(&host->lock);
>> @@ -1733,7 +1737,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;
>> @@ -1748,7 +1752,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.
>> @@ -2131,12 +2145,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;
>> @@ -2741,6 +2757,10 @@ int sdhci_add_host(struct sdhci_host *host)
>>       if (caps[1] & SDHCI_USE_SDR50_TUNING)
>>               host->flags |= SDHCI_SDR50_NEEDS_TUNING;
>>
>> +     /* Does the host needs 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;
>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> index 534974c..e76f649 100644
>> --- a/include/linux/mmc/card.h
>> +++ b/include/linux/mmc/card.h
>> @@ -209,6 +209,7 @@ struct mmc_card {
>>  #define MMC_STATE_HIGHSPEED_DDR (1<<4)               /* card is in high
>> speed mode */
>>  #define MMC_STATE_ULTRAHIGHSPEED (1<<5)              /* card is in ultra
>> high speed mode */
>>  #define MMC_CARD_SDXC                (1<<6)          /* card is SDXC */
>> +#define MMC_STATE_HIGHSPEED_200      (1<<7)  /* card is in HS200
>> mode */
>>       unsigned int            quirks;         /* card quirks */
>>  #define MMC_QUIRK_LENIENT_FN0        (1<<0)          /* allow SDIO FN0
>> writes outside of the VS CCCR range */
>>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func-
>> >cur_blksize */
>> @@ -365,6 +366,7 @@ static inline void __maybe_unused
>> remove_quirk(struct mmc_card *card, int data)
>>  #define mmc_card_present(c)  ((c)->state & MMC_STATE_PRESENT)
>>  #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
>>  #define mmc_card_highspeed(c)        ((c)->state & MMC_STATE_HIGHSPEED)
>> +#define mmc_card_hs200(c)    ((c)->state & MMC_STATE_HIGHSPEED_200)
>>  #define mmc_card_blockaddr(c)        ((c)->state & MMC_STATE_BLOCKADDR)
>>  #define mmc_card_ddr_mode(c) ((c)->state & MMC_STATE_HIGHSPEED_DDR)
>>  #define mmc_card_uhs(c)              ((c)->state &
>> MMC_STATE_ULTRAHIGHSPEED)
>> @@ -374,6 +376,7 @@ static inline void __maybe_unused
>> remove_quirk(struct mmc_card *card, int data)
>>  #define mmc_card_set_present(c)      ((c)->state |= MMC_STATE_PRESENT)
>>  #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
>>  #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
>> +#define mmc_card_set_hs200(c)        ((c)->state |=
>> MMC_STATE_HIGHSPEED_200)
>>  #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
>>  #define mmc_card_set_ddr_mode(c) ((c)->state |=
>> MMC_STATE_HIGHSPEED_DDR)
>>  #define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> index 706f722..5eac57a 100644
>> --- a/include/linux/mmc/host.h
>> +++ b/include/linux/mmc/host.h
>> @@ -50,6 +50,7 @@ struct mmc_ios {
>>
>>  #define MMC_TIMING_LEGACY    0
>>  #define MMC_TIMING_MMC_HS    1
>> +#define MMC_TIMING_MMC_HS200 2
>>  #define MMC_TIMING_SD_HS     2
>>  #define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY
>>  #define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS
>> @@ -60,6 +61,8 @@ struct mmc_ios {
>>  #define MMC_SDR_MODE         0
>>  #define MMC_1_2V_DDR_MODE    1
>>  #define MMC_1_8V_DDR_MODE    2
>> +#define MMC_1_2V_SDR_MODE    3
>> +#define MMC_1_8V_SDR_MODE    4
>>
>>       unsigned char   signal_voltage;         /* signalling voltage
>> (1.8V or 3.3V) */
>>
>> @@ -148,7 +151,9 @@ struct mmc_host_ops {
>>       void    (*init_card)(struct mmc_host *host, struct mmc_card *card);
>>
>>       int     (*start_signal_voltage_switch)(struct mmc_host *host,
>> struct mmc_ios *ios);
>> -     int     (*execute_tuning)(struct mmc_host *host);
>> +
>> +     /* The tuning command opcode value is different for SD and eMMC
>> cards */
>> +     int     (*execute_tuning)(struct mmc_host *host, u32 opcode);
>>       void    (*enable_preset_value)(struct mmc_host *host, bool enable);
>>       int     (*select_drive_strength)(unsigned int max_dtr, int
>> host_drv, int card_drv);
>>       void    (*hw_reset)(struct mmc_host *host);
>> @@ -242,6 +247,10 @@ struct mmc_host {
>>  #define MMC_CAP2_CACHE_CTRL  (1 << 1)        /* Allow cache control */
>>  #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)    /* Notify poweroff
>> supported */
>>  #define MMC_CAP2_NO_MULTI_READ       (1 << 3)        /* Multiblock reads
>> don't work */
>> +#define MMC_CAP2_HS200_1_8V_SDR      (1 << 4)        /* can support */
>> +#define MMC_CAP2_HS200_1_2V_SDR      (1 << 5)        /* can support */
>> +#define MMC_CAP2_HS200               (MMC_CAP2_HS200_1_8V_SDR | \
>> +                              MMC_CAP2_HS200_1_2V_SDR)
>>
>>       mmc_pm_flag_t           pm_caps;        /* supported pm features */
>>       unsigned int        power_notify_type;
>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> index 0e71356..7996272 100644
>> --- a/include/linux/mmc/mmc.h
>> +++ b/include/linux/mmc/mmc.h
>> @@ -51,6 +51,7 @@
>>  #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1
>> */
>>  #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1
>> */
>>  #define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1
>> */
>> +#define MMC_SEND_TUNING_BLOCK_HS200  21      /* adtc R1  */
>>
>>    /* class 3 */
>>  #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1
>> */
>> @@ -333,13 +334,76 @@ struct _mmc_csd {
>>
>>  #define EXT_CSD_CARD_TYPE_26 (1<<0)  /* Card can run at 26MHz */
>>  #define EXT_CSD_CARD_TYPE_52 (1<<1)  /* Card can run at 52MHz */
>> -#define EXT_CSD_CARD_TYPE_MASK       0xF     /* Mask out reserved bits */
>> +#define EXT_CSD_CARD_TYPE_MASK       0x3F    /* Mask out reserved bits */
>>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz
>> */
>>                                            /* DDR mode @1.8V or 3V I/O */
>>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz
>> */
>>                                            /* DDR mode @1.2V I/O */
>>  #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
>>                                       | EXT_CSD_CARD_TYPE_DDR_1_2V)
>> +#define EXT_CSD_CARD_TYPE_SDR_1_8V   (1<<4)  /* Card can run at
>> 200MHz */
>> +#define EXT_CSD_CARD_TYPE_SDR_1_2V   (1<<5)  /* Card can run at
>> 200MHz */
>> +                                             /* SDR mode @1.2V I/O */
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_200    (EXT_CSD_CARD_TYPE_SDR_1_8V     \
>> +                                     | EXT_CSD_CARD_TYPE_SDR_1_2V)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_ALL    (EXT_CSD_CARD_TYPE_SDR_200      \
>> +                                     | EXT_CSD_CARD_TYPE_52          \
>> +                                     | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define      EXT_CSD_CARD_TYPE_SDR_1_2V_ALL
>>       (EXT_CSD_CARD_TYPE_SDR_1_2V     \
>> +                                     | EXT_CSD_CARD_TYPE_52          \
>> +                                     | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define      EXT_CSD_CARD_TYPE_SDR_1_8V_ALL
>>       (EXT_CSD_CARD_TYPE_SDR_1_8V     \
>> +                                     | EXT_CSD_CARD_TYPE_52          \
>> +                                     | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V
>>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_1_8V
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V
>>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_1_8V
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V
>>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_1_2V
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V
>>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_1_2V
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52
>>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52
>>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V
>>       (EXT_CSD_CARD_TYPE_SDR_200   \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_1_8V
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V
>>       (EXT_CSD_CARD_TYPE_SDR_200   \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_1_2V
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52     (EXT_CSD_CARD_TYPE_SDR_200
>> \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>>
>>  #define EXT_CSD_BUS_WIDTH_1  0       /* Card is in 1 bit mode */
>>  #define EXT_CSD_BUS_WIDTH_4  1       /* Card is in 4 bit mode */
>> diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
>> index e4b6935..d9a2222 100644
>> --- a/include/linux/mmc/sdhci.h
>> +++ b/include/linux/mmc/sdhci.h
>> @@ -121,6 +121,7 @@ struct sdhci_host {
>>  #define SDHCI_AUTO_CMD23     (1<<7)  /* Auto CMD23 support */
>>  #define SDHCI_PV_ENABLED     (1<<8)  /* Preset value enabled */
>>  #define SDHCI_SDIO_IRQ_ENABLED       (1<<9)  /* SDIO irq enabled */
>> +#define SDHCI_HS200_NEEDS_TUNING (1<<10)     /* HS200 needs tuning */
>>
>>       unsigned int version;   /* SDHCI spec. version */
>>
>> --
>> 1.7.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
Subhash Jadavani Dec. 1, 2011, 10:57 a.m. UTC | #3
> -----Original Message-----
> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
> owner@vger.kernel.org] On Behalf Of Girish K S
> Sent: Thursday, December 01, 2011 3:58 PM
> To: Subhash Jadavani
> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
> soc@vger.kernel.org; Chris Ball
> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
> 
> On 1 December 2011 15:33, Subhash Jadavani <subhashj@codeaurora.org>
> wrote:
> > Hi Girish,
> >
> >> -----Original Message-----
> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
> >> owner@vger.kernel.org] On Behalf Of Girish K S
> >> Sent: Wednesday, November 30, 2011 2:24 PM
> >> To: linux-mmc@vger.kernel.org
> >> Cc: patches@linaro.org; linux-samsung-soc@vger.kernel.org;
> >> subhashj@codeaurora.org; Girish K S; Chris Ball
> >> Subject: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
> >>
> >> This patch adds the support of the HS200 bus speed for eMMC 4.5
> >> devices.
> >> The eMMC 4.5 devices have support for 200MHz bus speed.The mmc core
> and
> >> host modules have been touched to add support for this module.
> >>
> >> It is necessary to know the card type in the sdhci.c file to add
> >> support
> >> for eMMC tuning function. So card.h file is included to import the
> card
> >> data structure.
> >>
> >> cc: Chris Ball <cjb@laptop.org>
> >> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
> >> ---
> >> Changes in v5:
> >>       Reduced the case statements for better code readability.
> Removed
> >>       unused macro definitions. Modified the tuning function
> prototype
> >>       and definition to support tuning for both SD and eMMC cards.
> >> Changes in v4:
> >>       Rebased onto chris-mmc/mmc-next branch. This patch is
> >> successfully
> >>       applied on commit with id
> >> de022ed3fdc14808299b2fa66dbb1ed5ab921912.
> >> Changes in v3:
> >>       In the previous commits of chris-mmc/mmc-next branch, the
> patch
> >> with
> >>       commit id (c0f22a2c92e357e7cb3988b0b13034d70b7461f9) defines
> >> caps2 for
> >>       more capabilities. This patch version deletes the member
> >> ext_caps(created
> >>       in my earlier patch) from struct mmc_host and reuses already
> >> accepted
> >>       caps2 member.
> >> Changes in v2:
> >>       Rebased to latest chris-mmc/mmc-next branch. Resolved
> indentation
> >>       problems identified in review. This patch has to be applied
> >> before
> >>       the patch released for modifying the printk messages.
> >> Changes in v1:
> >>       Case statements in switch that produce same result have
> >>       been combined to reduce repeated assignments.
> >>       patch recreated after rebase to chris balls mmc-next branch.
> >>
> >>  drivers/mmc/core/bus.c    |    3 +-
> >>  drivers/mmc/core/mmc.c    |   77
> >> ++++++++++++++++++++++++++++++++++++++++----
> >>  drivers/mmc/core/sd.c     |    3 +-
> >>  drivers/mmc/core/sdio.c   |    4 ++-
> >>  drivers/mmc/host/sdhci.c  |   38 +++++++++++++++++-----
> >>  include/linux/mmc/card.h  |    3 ++
> >>  include/linux/mmc/host.h  |   11 ++++++-
> >>  include/linux/mmc/mmc.h   |   66
> >> ++++++++++++++++++++++++++++++++++++++-
> >>  include/linux/mmc/sdhci.h |    1 +
> >>  9 files changed, 185 insertions(+), 21 deletions(-)
> >>
> >> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> >> index 5639fdf..83c9f8d 100644
> >> --- a/drivers/mmc/core/bus.c
> >> +++ b/drivers/mmc/core/bus.c
> >> @@ -301,10 +301,11 @@ int mmc_add_card(struct mmc_card *card)
> >>                       mmc_card_ddr_mode(card) ? "DDR " : "",
> >>                       type);
> >>       } else {
> >> -             printk(KERN_INFO "%s: new %s%s%s card at address
> %04x\n",
> >> +             pr_info("%s: new %s%s%s%s card at address %04x\n",
> >>                       mmc_hostname(card->host),
> >>                       mmc_card_uhs(card) ? "ultra high speed " :
> >>                       (mmc_card_highspeed(card) ? "high speed " :
> ""),
> >> +                     (mmc_card_hs200(card) ? "HS200 " : ""),
> >>                       mmc_card_ddr_mode(card) ? "DDR " : "",
> >>                       type, card->rca);
> >>       }
> >> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> >> index a1223bd..f4124d6 100644
> >> --- a/drivers/mmc/core/mmc.c
> >> +++ b/drivers/mmc/core/mmc.c
> >> @@ -285,6 +285,27 @@ static int mmc_read_ext_csd(struct mmc_card
> *card,
> >> u8 *ext_csd)
> >>       }
> >>       card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
> >>       switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL:
> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
> >> +             card->ext_csd.hs_max_dtr = 200000000;
> >> +             card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
> >> +             break;
> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
> >> +             card->ext_csd.hs_max_dtr = 200000000;
> >> +             card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
> >> +             break;
> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
> >> +             card->ext_csd.hs_max_dtr = 200000000;
> >> +             card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
> >> +             break;
> >>       case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
> >>            EXT_CSD_CARD_TYPE_26:
> >>               card->ext_csd.hs_max_dtr = 52000000;
> >> @@ -699,6 +720,7 @@ static int mmc_init_card(struct mmc_host *host,
> u32
> >> ocr,
> >>  {
> >>       struct mmc_card *card;
> >>       int err, ddr = 0;
> >> +     int hs_sdr = 0;
> >>       u32 cid[4];
> >>       unsigned int max_dtr;
> >>       u32 rocr;
> >> @@ -894,11 +916,16 @@ static int mmc_init_card(struct mmc_host
> *host,
> >> u32 ocr,
> >>       /*
> >>        * Activate high speed (if supported)
> >>        */
> >> -     if ((card->ext_csd.hs_max_dtr != 0) &&
> >> -             (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
> >> -             err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> -                              EXT_CSD_HS_TIMING, 1,
> >> -                              card->ext_csd.generic_cmd6_time);
> >> +     if (card->ext_csd.hs_max_dtr != 0) {
> >> +             err = 0;
> >> +             if ((card->ext_csd.hs_max_dtr > 52000000) &&
> >> +                 (host->caps2 & MMC_CAP2_HS200))
> >> +                     err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> +                                      EXT_CSD_HS_TIMING, 2, 0);
> >> +             else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
> >> +                     err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> +                                      EXT_CSD_HS_TIMING, 1, 0);
> >> +
> >>               if (err && err != -EBADMSG)
> >>                       goto free_card;
> >>
> >> @@ -907,7 +934,11 @@ static int mmc_init_card(struct mmc_host *host,
> >> u32 ocr,
> >>                              mmc_hostname(card->host));
> >>                       err = 0;
> >>               } else {
> >> -                     mmc_card_set_highspeed(card);
> >> +                     if ((card->ext_csd.hs_max_dtr > 52000000) &&
> >> +                         (host->caps2 & MMC_CAP2_HS200))
> >> +                             mmc_card_set_hs200(card);
> >> +                     else
> >> +                             mmc_card_set_highspeed(card);
> >>                       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> >
> > MMC_TIMING_MMC_HS200 is defined but still not used.
> >
> > So I guess it should be like this ::
> >  +                      if ((card->ext_csd.hs_max_dtr > 52000000) &&
> >  +                          (host->caps2 & MMC_CAP2_HS200)) {
> >  +                              mmc_card_set_hs200(card);
> >  +                      mmc_set_timing(card->host,
> MMC_TIMING_MMC_HS200)
> >  +                      } else {
> >  +                              mmc_card_set_highspeed(card);
> >  +                              mmc_set_timing(card->host,
> > MMC_TIMING_MMC_HS)
> >  +                      }
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >>               }
> >>       }
> >> @@ -933,7 +964,7 @@ static int mmc_init_card(struct mmc_host *host,
> u32
> >> ocr,
> >>        */
> >>       max_dtr = (unsigned int)-1;
> >>
> >> -     if (mmc_card_highspeed(card)) {
> >> +     if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
> >>               if (max_dtr > card->ext_csd.hs_max_dtr)
> >>                       max_dtr = card->ext_csd.hs_max_dtr;
> >>       } else if (max_dtr > card->csd.max_dtr) {
> >> @@ -959,6 +990,18 @@ static int mmc_init_card(struct mmc_host *host,
> >> u32 ocr,
> >>       }
> >>
> >>       /*
> >> +      * Indicate HS200 SDR mode (if supported).
> >> +      */
> >> +     if (mmc_card_hs200(card)) {
> >> +             if ((card->ext_csd.card_type &
> EXT_CSD_CARD_TYPE_SDR_1_8V)
> >> +                     && (host->caps2 & MMC_CAP2_HS200_1_8V_SDR))
> >> +                             hs_sdr = MMC_1_8V_SDR_MODE;
> >> +             else if ((card->ext_csd.card_type &
> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
> >> +                     && (host->caps2 & MMC_CAP2_HS200_1_2V_SDR))
> >> +                             hs_sdr = MMC_1_2V_SDR_MODE;
> >> +     }
> >> +
> >> +     /*
> >>        * Activate wide bus and DDR (if supported).
> >>        */
> >>       if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
> >> @@ -998,6 +1041,17 @@ static int mmc_init_card(struct mmc_host
> *host,
> >> u32 ocr,
> >>                       if (!err) {
> >>                               mmc_set_bus_width(card->host,
> bus_width);
> >>
> >> +                             if ((host->caps2 & MMC_CAP2_HS200) &&
> >> +                                 card->host->ops->execute_tuning)
> >> +                                     err = card->host->ops-> \
> >> +                                           execute_tuning(card-
> >host,
> >> +
> > MMC_SEND_TUNING_BLOCK_HS200);
> >
> >
> > execute_tuning should be done right after the timing is changed to
> HS200 and
> > clock rate is changed to 200Mhz. This is not the correct sequence to
> call
> > the execute_tuning().
> > As told earlier, It is mentioned in the spec that tuning should be
> executed after change of buswidth (mandatory). Also it mentions that
> "The host may invoke the HS200 tuning sequence, by sending CMD21 to the
> device". It means that
>  after setting the HS200 mode, Changing to freq > 52Mhz and changing
> the bus width tuning can be executed anytime to identify the sampling
> point to read.(By anytime i mean before actual block read Operation).
> Can you please point me to the place in the spec where it specifies
> tuning should be done immediately after freq change (may be i missed
> to read it).


Ok. let me ask you this. Why do we run the execute_tuning()? It's to tune
the sampling clock generator of host controller before you start any read
operation (on command line or data line) from card. If you don't tune the
sampling clock generator before the read operation (after changing the
timing to HS200 and clock rate to 200mhz), you can't be sure that read
operation from card will be completed without errors. You may get the data /
cmd response CRC errors. At least this will surely fail on our MSM SDCC host
controller. That's what we had faced with SD3.0 UHS-I tuning as well as
mentioned in http://www.spinics.net/lists/linux-arm-msm/msg03867.html.


> >> +
> >> +                             if (err) {
> >> +                                     pr_warning("tuning execution
> > failed\n");
> >> +                                     continue;
> >> +                             }
> >> +
> >>                               /*
> >>                                * If controller can't handle bus
> width
> > test,
> >>                                * compare ext_csd previously read in
> 1 bit
> >> mode
> >> @@ -1056,6 +1110,15 @@ static int mmc_init_card(struct mmc_host
> *host,
> >> u32 ocr,
> >>                       mmc_card_set_ddr_mode(card);
> >>                       mmc_set_timing(card->host,
> MMC_TIMING_UHS_DDR50);
> >>                       mmc_set_bus_width(card->host, bus_width);
> >> +             } else if (hs_sdr) {
> >> +                     if (hs_sdr == EXT_CSD_CARD_TYPE_SDR_1_2V) {
> >> +                             err = mmc_set_signal_voltage(host,
> >> +                                     MMC_SIGNAL_VOLTAGE_120, 0);
> >> +                             if (err)
> >> +                                     goto err;
> >> +                     }
> >> +                     mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> >> +                     mmc_set_bus_width(card->host, bus_width);
> >>               }
> >>       }
> >>
> >> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> >> index 1d5a3bd..c1d3ee3 100644
> >> --- a/drivers/mmc/core/sd.c
> >> +++ b/drivers/mmc/core/sd.c
> >> @@ -660,7 +660,8 @@ static int mmc_sd_init_uhs_card(struct mmc_card
> >> *card)
> >>
> >>       /* SPI mode doesn't define CMD19 */
> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
> >> >execute_tuning)
> >> -             err = card->host->ops->execute_tuning(card->host);
> >> +             err = card->host->ops->execute_tuning(card->host,
>   \
> >> +
> > MMC_SEND_TUNING_BLOCK);
> >>
> >>  out:
> >>       kfree(status);
> >> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
> >> index 8c04f7f..8ef8817 100644
> >> --- a/drivers/mmc/core/sdio.c
> >> +++ b/drivers/mmc/core/sdio.c
> >> @@ -14,6 +14,7 @@
> >>
> >>  #include <linux/mmc/host.h>
> >>  #include <linux/mmc/card.h>
> >> +#include <linux/mmc/mmc.h>
> >>  #include <linux/mmc/sdio.h>
> >>  #include <linux/mmc/sdio_func.h>
> >>  #include <linux/mmc/sdio_ids.h>
> >> @@ -556,7 +557,8 @@ static int mmc_sdio_init_uhs_card(struct
> mmc_card
> >> *card)
> >>
> >>       /* Initialize and start re-tuning timer */
> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
> >> >execute_tuning)
> >> -             err = card->host->ops->execute_tuning(card->host);
> >> +             err = card->host->ops->execute_tuning(card->host,
> >> +
> > MMC_SEND_TUNING_BLOCK);
> >>
> >>  out:
> >>
> >> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> >> index a7c2311..13d74bb 100644
> >> --- a/drivers/mmc/host/sdhci.c
> >> +++ b/drivers/mmc/host/sdhci.c
> >> @@ -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
> >> @@ -1016,7 +1016,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 */
> >> @@ -1673,7 +1674,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;
> >> @@ -1694,10 +1695,13 @@ static int sdhci_execute_tuning(struct
> mmc_host
> >> *mmc)
> >>        * Host Controller needs tuning only in case of SDR104 mode
> >>        * and for SDR50 mode when Use Tuning for SDR50 is set in
> >>        * Capabilities register.
> >> +      * If the Host Controller supports the HS200 mode then tuning
> >> +      * function has to be executed.
> >>        */
> >>       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)))
> >> +         (host->flags & SDHCI_SDR50_NEEDS_TUNING)) ||
> >> +         (host->flags & SDHCI_HS200_NEEDS_TUNING))
> >>               ctrl |= SDHCI_CTRL_EXEC_TUNING;
> >>       else {
> >>               spin_unlock(&host->lock);
> >> @@ -1733,7 +1737,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;
> >> @@ -1748,7 +1752,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.
> >> @@ -2131,12 +2145,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;
> >> @@ -2741,6 +2757,10 @@ int sdhci_add_host(struct sdhci_host *host)
> >>       if (caps[1] & SDHCI_USE_SDR50_TUNING)
> >>               host->flags |= SDHCI_SDR50_NEEDS_TUNING;
> >>
> >> +     /* Does the host needs 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;
> >> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> >> index 534974c..e76f649 100644
> >> --- a/include/linux/mmc/card.h
> >> +++ b/include/linux/mmc/card.h
> >> @@ -209,6 +209,7 @@ struct mmc_card {
> >>  #define MMC_STATE_HIGHSPEED_DDR (1<<4)               /* card is in
> high
> >> speed mode */
> >>  #define MMC_STATE_ULTRAHIGHSPEED (1<<5)              /* card is in
> ultra
> >> high speed mode */
> >>  #define MMC_CARD_SDXC                (1<<6)          /* card is
> SDXC */
> >> +#define MMC_STATE_HIGHSPEED_200      (1<<7)  /* card is in HS200
> >> mode */
> >>       unsigned int            quirks;         /* card quirks */
> >>  #define MMC_QUIRK_LENIENT_FN0        (1<<0)          /* allow SDIO
> FN0
> >> writes outside of the VS CCCR range */
> >>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func-
> >> >cur_blksize */
> >> @@ -365,6 +366,7 @@ static inline void __maybe_unused
> >> remove_quirk(struct mmc_card *card, int data)
> >>  #define mmc_card_present(c)  ((c)->state & MMC_STATE_PRESENT)
> >>  #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
> >>  #define mmc_card_highspeed(c)        ((c)->state &
> MMC_STATE_HIGHSPEED)
> >> +#define mmc_card_hs200(c)    ((c)->state & MMC_STATE_HIGHSPEED_200)
> >>  #define mmc_card_blockaddr(c)        ((c)->state &
> MMC_STATE_BLOCKADDR)
> >>  #define mmc_card_ddr_mode(c) ((c)->state & MMC_STATE_HIGHSPEED_DDR)
> >>  #define mmc_card_uhs(c)              ((c)->state &
> >> MMC_STATE_ULTRAHIGHSPEED)
> >> @@ -374,6 +376,7 @@ static inline void __maybe_unused
> >> remove_quirk(struct mmc_card *card, int data)
> >>  #define mmc_card_set_present(c)      ((c)->state |=
> MMC_STATE_PRESENT)
> >>  #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
> >>  #define mmc_card_set_highspeed(c) ((c)->state |=
> MMC_STATE_HIGHSPEED)
> >> +#define mmc_card_set_hs200(c)        ((c)->state |=
> >> MMC_STATE_HIGHSPEED_200)
> >>  #define mmc_card_set_blockaddr(c) ((c)->state |=
> MMC_STATE_BLOCKADDR)
> >>  #define mmc_card_set_ddr_mode(c) ((c)->state |=
> >> MMC_STATE_HIGHSPEED_DDR)
> >>  #define mmc_card_set_uhs(c) ((c)->state |=
> MMC_STATE_ULTRAHIGHSPEED)
> >> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> >> index 706f722..5eac57a 100644
> >> --- a/include/linux/mmc/host.h
> >> +++ b/include/linux/mmc/host.h
> >> @@ -50,6 +50,7 @@ struct mmc_ios {
> >>
> >>  #define MMC_TIMING_LEGACY    0
> >>  #define MMC_TIMING_MMC_HS    1
> >> +#define MMC_TIMING_MMC_HS200 2
> >>  #define MMC_TIMING_SD_HS     2
> >>  #define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY
> >>  #define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS
> >> @@ -60,6 +61,8 @@ struct mmc_ios {
> >>  #define MMC_SDR_MODE         0
> >>  #define MMC_1_2V_DDR_MODE    1
> >>  #define MMC_1_8V_DDR_MODE    2
> >> +#define MMC_1_2V_SDR_MODE    3
> >> +#define MMC_1_8V_SDR_MODE    4
> >>
> >>       unsigned char   signal_voltage;         /* signalling voltage
> >> (1.8V or 3.3V) */
> >>
> >> @@ -148,7 +151,9 @@ struct mmc_host_ops {
> >>       void    (*init_card)(struct mmc_host *host, struct mmc_card
> *card);
> >>
> >>       int     (*start_signal_voltage_switch)(struct mmc_host *host,
> >> struct mmc_ios *ios);
> >> -     int     (*execute_tuning)(struct mmc_host *host);
> >> +
> >> +     /* The tuning command opcode value is different for SD and
> eMMC
> >> cards */
> >> +     int     (*execute_tuning)(struct mmc_host *host, u32 opcode);
> >>       void    (*enable_preset_value)(struct mmc_host *host, bool
> enable);
> >>       int     (*select_drive_strength)(unsigned int max_dtr, int
> >> host_drv, int card_drv);
> >>       void    (*hw_reset)(struct mmc_host *host);
> >> @@ -242,6 +247,10 @@ struct mmc_host {
> >>  #define MMC_CAP2_CACHE_CTRL  (1 << 1)        /* Allow cache control
> */
> >>  #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)    /* Notify poweroff
> >> supported */
> >>  #define MMC_CAP2_NO_MULTI_READ       (1 << 3)        /* Multiblock
> reads
> >> don't work */
> >> +#define MMC_CAP2_HS200_1_8V_SDR      (1 << 4)        /* can support
> */
> >> +#define MMC_CAP2_HS200_1_2V_SDR      (1 << 5)        /* can support
> */
> >> +#define MMC_CAP2_HS200               (MMC_CAP2_HS200_1_8V_SDR | \
> >> +                              MMC_CAP2_HS200_1_2V_SDR)
> >>
> >>       mmc_pm_flag_t           pm_caps;        /* supported pm
> features */
> >>       unsigned int        power_notify_type;
> >> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> >> index 0e71356..7996272 100644
> >> --- a/include/linux/mmc/mmc.h
> >> +++ b/include/linux/mmc/mmc.h
> >> @@ -51,6 +51,7 @@
> >>  #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1
> >> */
> >>  #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1
> >> */
> >>  #define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1
> >> */
> >> +#define MMC_SEND_TUNING_BLOCK_HS200  21      /* adtc R1  */
> >>
> >>    /* class 3 */
> >>  #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1
> >> */
> >> @@ -333,13 +334,76 @@ struct _mmc_csd {
> >>
> >>  #define EXT_CSD_CARD_TYPE_26 (1<<0)  /* Card can run at 26MHz */
> >>  #define EXT_CSD_CARD_TYPE_52 (1<<1)  /* Card can run at 52MHz */
> >> -#define EXT_CSD_CARD_TYPE_MASK       0xF     /* Mask out reserved
> bits */
> >> +#define EXT_CSD_CARD_TYPE_MASK       0x3F    /* Mask out reserved
> bits */
> >>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at
> 52MHz
> >> */
> >>                                            /* DDR mode @1.8V or 3V
> I/O */
> >>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at
> 52MHz
> >> */
> >>                                            /* DDR mode @1.2V I/O */
> >>  #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V
>  \
> >>                                       | EXT_CSD_CARD_TYPE_DDR_1_2V)
> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V   (1<<4)  /* Card can run at
> >> 200MHz */
> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V   (1<<5)  /* Card can run at
> >> 200MHz */
> >> +                                             /* SDR mode @1.2V I/O
> */
> >> +
> >> +#define EXT_CSD_CARD_TYPE_SDR_200    (EXT_CSD_CARD_TYPE_SDR_1_8V
>   \
> >> +                                     | EXT_CSD_CARD_TYPE_SDR_1_2V)
> >> +
> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL    (EXT_CSD_CARD_TYPE_SDR_200
>  \
> >> +                                     | EXT_CSD_CARD_TYPE_52
>  \
> >> +                                     | EXT_CSD_CARD_TYPE_26)
> >> +
> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_2V_ALL
> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V     \
> >> +                                     | EXT_CSD_CARD_TYPE_52
>  \
> >> +                                     | EXT_CSD_CARD_TYPE_26)
> >> +
> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_8V_ALL
> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V     \
> >> +                                     | EXT_CSD_CARD_TYPE_52
>  \
> >> +                                     | EXT_CSD_CARD_TYPE_26)
> >> +
> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V
> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
> >> +                                             |
> EXT_CSD_CARD_TYPE_DDR_1_8V
> > \
> >> +                                             | EXT_CSD_CARD_TYPE_52
> > \
> >> +                                             |
> EXT_CSD_CARD_TYPE_26)
> >> +
> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V
> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
> >> +                                             |
> EXT_CSD_CARD_TYPE_DDR_1_8V
> > \
> >> +                                             | EXT_CSD_CARD_TYPE_52
> > \
> >> +                                             |
> EXT_CSD_CARD_TYPE_26)
> >> +
> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V
> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
> >> +                                             |
> EXT_CSD_CARD_TYPE_DDR_1_2V
> > \
> >> +                                             | EXT_CSD_CARD_TYPE_52
> > \
> >> +                                             |
> EXT_CSD_CARD_TYPE_26)
> >> +
> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V
> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
> >> +                                             |
> EXT_CSD_CARD_TYPE_DDR_1_2V
> > \
> >> +                                             | EXT_CSD_CARD_TYPE_52
> > \
> >> +                                             |
> EXT_CSD_CARD_TYPE_26)
> >> +
> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52
> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
> >> +                                             |
> EXT_CSD_CARD_TYPE_DDR_52
> > \
> >> +                                             | EXT_CSD_CARD_TYPE_52
> > \
> >> +                                             |
> EXT_CSD_CARD_TYPE_26)
> >> +
> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52
> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
> >> +                                             |
> EXT_CSD_CARD_TYPE_DDR_52
> > \
> >> +                                             | EXT_CSD_CARD_TYPE_52
> > \
> >> +                                             |
> EXT_CSD_CARD_TYPE_26)
> >> +
> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V
> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
> >> +                                             |
> EXT_CSD_CARD_TYPE_DDR_1_8V
> > \
> >> +                                             | EXT_CSD_CARD_TYPE_52
> > \
> >> +                                             |
> EXT_CSD_CARD_TYPE_26)
> >> +
> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V
> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
> >> +                                             |
> EXT_CSD_CARD_TYPE_DDR_1_2V
> > \
> >> +                                             | EXT_CSD_CARD_TYPE_52
> > \
> >> +                                             |
> EXT_CSD_CARD_TYPE_26)
> >> +
> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52
> (EXT_CSD_CARD_TYPE_SDR_200
> >> \
> >> +                                             |
> EXT_CSD_CARD_TYPE_DDR_52
> > \
> >> +                                             | EXT_CSD_CARD_TYPE_52
> > \
> >> +                                             |
> EXT_CSD_CARD_TYPE_26)
> >>
> >>  #define EXT_CSD_BUS_WIDTH_1  0       /* Card is in 1 bit mode */
> >>  #define EXT_CSD_BUS_WIDTH_4  1       /* Card is in 4 bit mode */
> >> diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
> >> index e4b6935..d9a2222 100644
> >> --- a/include/linux/mmc/sdhci.h
> >> +++ b/include/linux/mmc/sdhci.h
> >> @@ -121,6 +121,7 @@ struct sdhci_host {
> >>  #define SDHCI_AUTO_CMD23     (1<<7)  /* Auto CMD23 support */
> >>  #define SDHCI_PV_ENABLED     (1<<8)  /* Preset value enabled */
> >>  #define SDHCI_SDIO_IRQ_ENABLED       (1<<9)  /* SDIO irq enabled */
> >> +#define SDHCI_HS200_NEEDS_TUNING (1<<10)     /* HS200 needs tuning
> */
> >>
> >>       unsigned int version;   /* SDHCI spec. version */
> >>
> >> --
> >> 1.7.1
> >>
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc"
> in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-mmc"
> in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Girish K S Dec. 1, 2011, 2:18 p.m. UTC | #4
On 1 December 2011 16:27, Subhash Jadavani <subhashj@codeaurora.org> wrote:
>
>
>> -----Original Message-----
>> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>> owner@vger.kernel.org] On Behalf Of Girish K S
>> Sent: Thursday, December 01, 2011 3:58 PM
>> To: Subhash Jadavani
>> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>> soc@vger.kernel.org; Chris Ball
>> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>>
>> On 1 December 2011 15:33, Subhash Jadavani <subhashj@codeaurora.org>
>> wrote:
>> > Hi Girish,
>> >
>> >> -----Original Message-----
>> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>> >> owner@vger.kernel.org] On Behalf Of Girish K S
>> >> Sent: Wednesday, November 30, 2011 2:24 PM
>> >> To: linux-mmc@vger.kernel.org
>> >> Cc: patches@linaro.org; linux-samsung-soc@vger.kernel.org;
>> >> subhashj@codeaurora.org; Girish K S; Chris Ball
>> >> Subject: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>> >>
>> >> This patch adds the support of the HS200 bus speed for eMMC 4.5
>> >> devices.
>> >> The eMMC 4.5 devices have support for 200MHz bus speed.The mmc core
>> and
>> >> host modules have been touched to add support for this module.
>> >>
>> >> It is necessary to know the card type in the sdhci.c file to add
>> >> support
>> >> for eMMC tuning function. So card.h file is included to import the
>> card
>> >> data structure.
>> >>
>> >> cc: Chris Ball <cjb@laptop.org>
>> >> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
>> >> ---
>> >> Changes in v5:
>> >>       Reduced the case statements for better code readability.
>> Removed
>> >>       unused macro definitions. Modified the tuning function
>> prototype
>> >>       and definition to support tuning for both SD and eMMC cards.
>> >> Changes in v4:
>> >>       Rebased onto chris-mmc/mmc-next branch. This patch is
>> >> successfully
>> >>       applied on commit with id
>> >> de022ed3fdc14808299b2fa66dbb1ed5ab921912.
>> >> Changes in v3:
>> >>       In the previous commits of chris-mmc/mmc-next branch, the
>> patch
>> >> with
>> >>       commit id (c0f22a2c92e357e7cb3988b0b13034d70b7461f9) defines
>> >> caps2 for
>> >>       more capabilities. This patch version deletes the member
>> >> ext_caps(created
>> >>       in my earlier patch) from struct mmc_host and reuses already
>> >> accepted
>> >>       caps2 member.
>> >> Changes in v2:
>> >>       Rebased to latest chris-mmc/mmc-next branch. Resolved
>> indentation
>> >>       problems identified in review. This patch has to be applied
>> >> before
>> >>       the patch released for modifying the printk messages.
>> >> Changes in v1:
>> >>       Case statements in switch that produce same result have
>> >>       been combined to reduce repeated assignments.
>> >>       patch recreated after rebase to chris balls mmc-next branch.
>> >>
>> >>  drivers/mmc/core/bus.c    |    3 +-
>> >>  drivers/mmc/core/mmc.c    |   77
>> >> ++++++++++++++++++++++++++++++++++++++++----
>> >>  drivers/mmc/core/sd.c     |    3 +-
>> >>  drivers/mmc/core/sdio.c   |    4 ++-
>> >>  drivers/mmc/host/sdhci.c  |   38 +++++++++++++++++-----
>> >>  include/linux/mmc/card.h  |    3 ++
>> >>  include/linux/mmc/host.h  |   11 ++++++-
>> >>  include/linux/mmc/mmc.h   |   66
>> >> ++++++++++++++++++++++++++++++++++++++-
>> >>  include/linux/mmc/sdhci.h |    1 +
>> >>  9 files changed, 185 insertions(+), 21 deletions(-)
>> >>
>> >> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> >> index 5639fdf..83c9f8d 100644
>> >> --- a/drivers/mmc/core/bus.c
>> >> +++ b/drivers/mmc/core/bus.c
>> >> @@ -301,10 +301,11 @@ int mmc_add_card(struct mmc_card *card)
>> >>                       mmc_card_ddr_mode(card) ? "DDR " : "",
>> >>                       type);
>> >>       } else {
>> >> -             printk(KERN_INFO "%s: new %s%s%s card at address
>> %04x\n",
>> >> +             pr_info("%s: new %s%s%s%s card at address %04x\n",
>> >>                       mmc_hostname(card->host),
>> >>                       mmc_card_uhs(card) ? "ultra high speed " :
>> >>                       (mmc_card_highspeed(card) ? "high speed " :
>> ""),
>> >> +                     (mmc_card_hs200(card) ? "HS200 " : ""),
>> >>                       mmc_card_ddr_mode(card) ? "DDR " : "",
>> >>                       type, card->rca);
>> >>       }
>> >> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> >> index a1223bd..f4124d6 100644
>> >> --- a/drivers/mmc/core/mmc.c
>> >> +++ b/drivers/mmc/core/mmc.c
>> >> @@ -285,6 +285,27 @@ static int mmc_read_ext_csd(struct mmc_card
>> *card,
>> >> u8 *ext_csd)
>> >>       }
>> >>       card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>> >>       switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
>> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL:
>> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
>> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
>> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
>> >> +             card->ext_csd.hs_max_dtr = 200000000;
>> >> +             card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
>> >> +             break;
>> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
>> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
>> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
>> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
>> >> +             card->ext_csd.hs_max_dtr = 200000000;
>> >> +             card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
>> >> +             break;
>> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
>> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
>> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
>> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
>> >> +             card->ext_csd.hs_max_dtr = 200000000;
>> >> +             card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
>> >> +             break;
>> >>       case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
>> >>            EXT_CSD_CARD_TYPE_26:
>> >>               card->ext_csd.hs_max_dtr = 52000000;
>> >> @@ -699,6 +720,7 @@ static int mmc_init_card(struct mmc_host *host,
>> u32
>> >> ocr,
>> >>  {
>> >>       struct mmc_card *card;
>> >>       int err, ddr = 0;
>> >> +     int hs_sdr = 0;
>> >>       u32 cid[4];
>> >>       unsigned int max_dtr;
>> >>       u32 rocr;
>> >> @@ -894,11 +916,16 @@ static int mmc_init_card(struct mmc_host
>> *host,
>> >> u32 ocr,
>> >>       /*
>> >>        * Activate high speed (if supported)
>> >>        */
>> >> -     if ((card->ext_csd.hs_max_dtr != 0) &&
>> >> -             (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
>> >> -             err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> -                              EXT_CSD_HS_TIMING, 1,
>> >> -                              card->ext_csd.generic_cmd6_time);
>> >> +     if (card->ext_csd.hs_max_dtr != 0) {
>> >> +             err = 0;
>> >> +             if ((card->ext_csd.hs_max_dtr > 52000000) &&
>> >> +                 (host->caps2 & MMC_CAP2_HS200))
>> >> +                     err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> +                                      EXT_CSD_HS_TIMING, 2, 0);
>> >> +             else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
>> >> +                     err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> +                                      EXT_CSD_HS_TIMING, 1, 0);
>> >> +
>> >>               if (err && err != -EBADMSG)
>> >>                       goto free_card;
>> >>
>> >> @@ -907,7 +934,11 @@ static int mmc_init_card(struct mmc_host *host,
>> >> u32 ocr,
>> >>                              mmc_hostname(card->host));
>> >>                       err = 0;
>> >>               } else {
>> >> -                     mmc_card_set_highspeed(card);
>> >> +                     if ((card->ext_csd.hs_max_dtr > 52000000) &&
>> >> +                         (host->caps2 & MMC_CAP2_HS200))
>> >> +                             mmc_card_set_hs200(card);
>> >> +                     else
>> >> +                             mmc_card_set_highspeed(card);
>> >>                       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> >
>> > MMC_TIMING_MMC_HS200 is defined but still not used.
>> >
>> > So I guess it should be like this ::
>> >  +                      if ((card->ext_csd.hs_max_dtr > 52000000) &&
>> >  +                          (host->caps2 & MMC_CAP2_HS200)) {
>> >  +                              mmc_card_set_hs200(card);
>> >  +                      mmc_set_timing(card->host,
>> MMC_TIMING_MMC_HS200)
>> >  +                      } else {
>> >  +                              mmc_card_set_highspeed(card);
>> >  +                              mmc_set_timing(card->host,
>> > MMC_TIMING_MMC_HS)
>> >  +                      }
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >>               }
>> >>       }
>> >> @@ -933,7 +964,7 @@ static int mmc_init_card(struct mmc_host *host,
>> u32
>> >> ocr,
>> >>        */
>> >>       max_dtr = (unsigned int)-1;
>> >>
>> >> -     if (mmc_card_highspeed(card)) {
>> >> +     if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
>> >>               if (max_dtr > card->ext_csd.hs_max_dtr)
>> >>                       max_dtr = card->ext_csd.hs_max_dtr;
>> >>       } else if (max_dtr > card->csd.max_dtr) {
>> >> @@ -959,6 +990,18 @@ static int mmc_init_card(struct mmc_host *host,
>> >> u32 ocr,
>> >>       }
>> >>
>> >>       /*
>> >> +      * Indicate HS200 SDR mode (if supported).
>> >> +      */
>> >> +     if (mmc_card_hs200(card)) {
>> >> +             if ((card->ext_csd.card_type &
>> EXT_CSD_CARD_TYPE_SDR_1_8V)
>> >> +                     && (host->caps2 & MMC_CAP2_HS200_1_8V_SDR))
>> >> +                             hs_sdr = MMC_1_8V_SDR_MODE;
>> >> +             else if ((card->ext_csd.card_type &
>> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
>> >> +                     && (host->caps2 & MMC_CAP2_HS200_1_2V_SDR))
>> >> +                             hs_sdr = MMC_1_2V_SDR_MODE;
>> >> +     }
>> >> +
>> >> +     /*
>> >>        * Activate wide bus and DDR (if supported).
>> >>        */
>> >>       if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
>> >> @@ -998,6 +1041,17 @@ static int mmc_init_card(struct mmc_host
>> *host,
>> >> u32 ocr,
>> >>                       if (!err) {
>> >>                               mmc_set_bus_width(card->host,
>> bus_width);
>> >>
>> >> +                             if ((host->caps2 & MMC_CAP2_HS200) &&
>> >> +                                 card->host->ops->execute_tuning)
>> >> +                                     err = card->host->ops-> \
>> >> +                                           execute_tuning(card-
>> >host,
>> >> +
>> > MMC_SEND_TUNING_BLOCK_HS200);
>> >
>> >
>> > execute_tuning should be done right after the timing is changed to
>> HS200 and
>> > clock rate is changed to 200Mhz. This is not the correct sequence to
>> call
>> > the execute_tuning().
>> > As told earlier, It is mentioned in the spec that tuning should be
>> executed after change of buswidth (mandatory). Also it mentions that
>> "The host may invoke the HS200 tuning sequence, by sending CMD21 to the
>> device". It means that
>>  after setting the HS200 mode, Changing to freq > 52Mhz and changing
>> the bus width tuning can be executed anytime to identify the sampling
>> point to read.(By anytime i mean before actual block read Operation).
>> Can you please point me to the place in the spec where it specifies
>> tuning should be done immediately after freq change (may be i missed
>> to read it).
>
>
> Ok. let me ask you this. Why do we run the execute_tuning()? It's to tune
> the sampling clock generator of host controller before you start any read
> operation (on command line or data line) from card. If you don't tune the
> sampling clock generator before the read operation (after changing the
> timing to HS200 and clock rate to 200mhz), you can't be sure that read
> operation from card will be completed without errors. You may get the data /
> cmd response CRC errors. At least this will surely fail on our MSM SDCC host
> controller. That's what we had faced with SD3.0 UHS-I tuning as well as
> mentioned in http://www.spinics.net/lists/linux-arm-msm/msg03867.html.
> this tuning is done before any read opration for the best bus width supported.
ps:Chris need your comment on this
>
>> >> +
>> >> +                             if (err) {
>> >> +                                     pr_warning("tuning execution
>> > failed\n");
>> >> +                                     continue;
>> >> +                             }
>> >> +
>> >>                               /*
>> >>                                * If controller can't handle bus
>> width
>> > test,
>> >>                                * compare ext_csd previously read in
>> 1 bit
>> >> mode
>> >> @@ -1056,6 +1110,15 @@ static int mmc_init_card(struct mmc_host
>> *host,
>> >> u32 ocr,
>> >>                       mmc_card_set_ddr_mode(card);
>> >>                       mmc_set_timing(card->host,
>> MMC_TIMING_UHS_DDR50);
>> >>                       mmc_set_bus_width(card->host, bus_width);
>> >> +             } else if (hs_sdr) {
>> >> +                     if (hs_sdr == EXT_CSD_CARD_TYPE_SDR_1_2V) {
>> >> +                             err = mmc_set_signal_voltage(host,
>> >> +                                     MMC_SIGNAL_VOLTAGE_120, 0);
>> >> +                             if (err)
>> >> +                                     goto err;
>> >> +                     }
>> >> +                     mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> >> +                     mmc_set_bus_width(card->host, bus_width);
>> >>               }
>> >>       }
>> >>
>> >> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
>> >> index 1d5a3bd..c1d3ee3 100644
>> >> --- a/drivers/mmc/core/sd.c
>> >> +++ b/drivers/mmc/core/sd.c
>> >> @@ -660,7 +660,8 @@ static int mmc_sd_init_uhs_card(struct mmc_card
>> >> *card)
>> >>
>> >>       /* SPI mode doesn't define CMD19 */
>> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
>> >> >execute_tuning)
>> >> -             err = card->host->ops->execute_tuning(card->host);
>> >> +             err = card->host->ops->execute_tuning(card->host,
>>   \
>> >> +
>> > MMC_SEND_TUNING_BLOCK);
>> >>
>> >>  out:
>> >>       kfree(status);
>> >> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
>> >> index 8c04f7f..8ef8817 100644
>> >> --- a/drivers/mmc/core/sdio.c
>> >> +++ b/drivers/mmc/core/sdio.c
>> >> @@ -14,6 +14,7 @@
>> >>
>> >>  #include <linux/mmc/host.h>
>> >>  #include <linux/mmc/card.h>
>> >> +#include <linux/mmc/mmc.h>
>> >>  #include <linux/mmc/sdio.h>
>> >>  #include <linux/mmc/sdio_func.h>
>> >>  #include <linux/mmc/sdio_ids.h>
>> >> @@ -556,7 +557,8 @@ static int mmc_sdio_init_uhs_card(struct
>> mmc_card
>> >> *card)
>> >>
>> >>       /* Initialize and start re-tuning timer */
>> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
>> >> >execute_tuning)
>> >> -             err = card->host->ops->execute_tuning(card->host);
>> >> +             err = card->host->ops->execute_tuning(card->host,
>> >> +
>> > MMC_SEND_TUNING_BLOCK);
>> >>
>> >>  out:
>> >>
>> >> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>> >> index a7c2311..13d74bb 100644
>> >> --- a/drivers/mmc/host/sdhci.c
>> >> +++ b/drivers/mmc/host/sdhci.c
>> >> @@ -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
>> >> @@ -1016,7 +1016,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 */
>> >> @@ -1673,7 +1674,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;
>> >> @@ -1694,10 +1695,13 @@ static int sdhci_execute_tuning(struct
>> mmc_host
>> >> *mmc)
>> >>        * Host Controller needs tuning only in case of SDR104 mode
>> >>        * and for SDR50 mode when Use Tuning for SDR50 is set in
>> >>        * Capabilities register.
>> >> +      * If the Host Controller supports the HS200 mode then tuning
>> >> +      * function has to be executed.
>> >>        */
>> >>       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)))
>> >> +         (host->flags & SDHCI_SDR50_NEEDS_TUNING)) ||
>> >> +         (host->flags & SDHCI_HS200_NEEDS_TUNING))
>> >>               ctrl |= SDHCI_CTRL_EXEC_TUNING;
>> >>       else {
>> >>               spin_unlock(&host->lock);
>> >> @@ -1733,7 +1737,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;
>> >> @@ -1748,7 +1752,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.
>> >> @@ -2131,12 +2145,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;
>> >> @@ -2741,6 +2757,10 @@ int sdhci_add_host(struct sdhci_host *host)
>> >>       if (caps[1] & SDHCI_USE_SDR50_TUNING)
>> >>               host->flags |= SDHCI_SDR50_NEEDS_TUNING;
>> >>
>> >> +     /* Does the host needs 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;
>> >> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> >> index 534974c..e76f649 100644
>> >> --- a/include/linux/mmc/card.h
>> >> +++ b/include/linux/mmc/card.h
>> >> @@ -209,6 +209,7 @@ struct mmc_card {
>> >>  #define MMC_STATE_HIGHSPEED_DDR (1<<4)               /* card is in
>> high
>> >> speed mode */
>> >>  #define MMC_STATE_ULTRAHIGHSPEED (1<<5)              /* card is in
>> ultra
>> >> high speed mode */
>> >>  #define MMC_CARD_SDXC                (1<<6)          /* card is
>> SDXC */
>> >> +#define MMC_STATE_HIGHSPEED_200      (1<<7)  /* card is in HS200
>> >> mode */
>> >>       unsigned int            quirks;         /* card quirks */
>> >>  #define MMC_QUIRK_LENIENT_FN0        (1<<0)          /* allow SDIO
>> FN0
>> >> writes outside of the VS CCCR range */
>> >>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func-
>> >> >cur_blksize */
>> >> @@ -365,6 +366,7 @@ static inline void __maybe_unused
>> >> remove_quirk(struct mmc_card *card, int data)
>> >>  #define mmc_card_present(c)  ((c)->state & MMC_STATE_PRESENT)
>> >>  #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
>> >>  #define mmc_card_highspeed(c)        ((c)->state &
>> MMC_STATE_HIGHSPEED)
>> >> +#define mmc_card_hs200(c)    ((c)->state & MMC_STATE_HIGHSPEED_200)
>> >>  #define mmc_card_blockaddr(c)        ((c)->state &
>> MMC_STATE_BLOCKADDR)
>> >>  #define mmc_card_ddr_mode(c) ((c)->state & MMC_STATE_HIGHSPEED_DDR)
>> >>  #define mmc_card_uhs(c)              ((c)->state &
>> >> MMC_STATE_ULTRAHIGHSPEED)
>> >> @@ -374,6 +376,7 @@ static inline void __maybe_unused
>> >> remove_quirk(struct mmc_card *card, int data)
>> >>  #define mmc_card_set_present(c)      ((c)->state |=
>> MMC_STATE_PRESENT)
>> >>  #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
>> >>  #define mmc_card_set_highspeed(c) ((c)->state |=
>> MMC_STATE_HIGHSPEED)
>> >> +#define mmc_card_set_hs200(c)        ((c)->state |=
>> >> MMC_STATE_HIGHSPEED_200)
>> >>  #define mmc_card_set_blockaddr(c) ((c)->state |=
>> MMC_STATE_BLOCKADDR)
>> >>  #define mmc_card_set_ddr_mode(c) ((c)->state |=
>> >> MMC_STATE_HIGHSPEED_DDR)
>> >>  #define mmc_card_set_uhs(c) ((c)->state |=
>> MMC_STATE_ULTRAHIGHSPEED)
>> >> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> >> index 706f722..5eac57a 100644
>> >> --- a/include/linux/mmc/host.h
>> >> +++ b/include/linux/mmc/host.h
>> >> @@ -50,6 +50,7 @@ struct mmc_ios {
>> >>
>> >>  #define MMC_TIMING_LEGACY    0
>> >>  #define MMC_TIMING_MMC_HS    1
>> >> +#define MMC_TIMING_MMC_HS200 2
>> >>  #define MMC_TIMING_SD_HS     2
>> >>  #define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY
>> >>  #define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS
>> >> @@ -60,6 +61,8 @@ struct mmc_ios {
>> >>  #define MMC_SDR_MODE         0
>> >>  #define MMC_1_2V_DDR_MODE    1
>> >>  #define MMC_1_8V_DDR_MODE    2
>> >> +#define MMC_1_2V_SDR_MODE    3
>> >> +#define MMC_1_8V_SDR_MODE    4
>> >>
>> >>       unsigned char   signal_voltage;         /* signalling voltage
>> >> (1.8V or 3.3V) */
>> >>
>> >> @@ -148,7 +151,9 @@ struct mmc_host_ops {
>> >>       void    (*init_card)(struct mmc_host *host, struct mmc_card
>> *card);
>> >>
>> >>       int     (*start_signal_voltage_switch)(struct mmc_host *host,
>> >> struct mmc_ios *ios);
>> >> -     int     (*execute_tuning)(struct mmc_host *host);
>> >> +
>> >> +     /* The tuning command opcode value is different for SD and
>> eMMC
>> >> cards */
>> >> +     int     (*execute_tuning)(struct mmc_host *host, u32 opcode);
>> >>       void    (*enable_preset_value)(struct mmc_host *host, bool
>> enable);
>> >>       int     (*select_drive_strength)(unsigned int max_dtr, int
>> >> host_drv, int card_drv);
>> >>       void    (*hw_reset)(struct mmc_host *host);
>> >> @@ -242,6 +247,10 @@ struct mmc_host {
>> >>  #define MMC_CAP2_CACHE_CTRL  (1 << 1)        /* Allow cache control
>> */
>> >>  #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)    /* Notify poweroff
>> >> supported */
>> >>  #define MMC_CAP2_NO_MULTI_READ       (1 << 3)        /* Multiblock
>> reads
>> >> don't work */
>> >> +#define MMC_CAP2_HS200_1_8V_SDR      (1 << 4)        /* can support
>> */
>> >> +#define MMC_CAP2_HS200_1_2V_SDR      (1 << 5)        /* can support
>> */
>> >> +#define MMC_CAP2_HS200               (MMC_CAP2_HS200_1_8V_SDR | \
>> >> +                              MMC_CAP2_HS200_1_2V_SDR)
>> >>
>> >>       mmc_pm_flag_t           pm_caps;        /* supported pm
>> features */
>> >>       unsigned int        power_notify_type;
>> >> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> >> index 0e71356..7996272 100644
>> >> --- a/include/linux/mmc/mmc.h
>> >> +++ b/include/linux/mmc/mmc.h
>> >> @@ -51,6 +51,7 @@
>> >>  #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1
>> >> */
>> >>  #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1
>> >> */
>> >>  #define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1
>> >> */
>> >> +#define MMC_SEND_TUNING_BLOCK_HS200  21      /* adtc R1  */
>> >>
>> >>    /* class 3 */
>> >>  #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1
>> >> */
>> >> @@ -333,13 +334,76 @@ struct _mmc_csd {
>> >>
>> >>  #define EXT_CSD_CARD_TYPE_26 (1<<0)  /* Card can run at 26MHz */
>> >>  #define EXT_CSD_CARD_TYPE_52 (1<<1)  /* Card can run at 52MHz */
>> >> -#define EXT_CSD_CARD_TYPE_MASK       0xF     /* Mask out reserved
>> bits */
>> >> +#define EXT_CSD_CARD_TYPE_MASK       0x3F    /* Mask out reserved
>> bits */
>> >>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at
>> 52MHz
>> >> */
>> >>                                            /* DDR mode @1.8V or 3V
>> I/O */
>> >>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at
>> 52MHz
>> >> */
>> >>                                            /* DDR mode @1.2V I/O */
>> >>  #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V
>>  \
>> >>                                       | EXT_CSD_CARD_TYPE_DDR_1_2V)
>> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V   (1<<4)  /* Card can run at
>> >> 200MHz */
>> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V   (1<<5)  /* Card can run at
>> >> 200MHz */
>> >> +                                             /* SDR mode @1.2V I/O
>> */
>> >> +
>> >> +#define EXT_CSD_CARD_TYPE_SDR_200    (EXT_CSD_CARD_TYPE_SDR_1_8V
>>   \
>> >> +                                     | EXT_CSD_CARD_TYPE_SDR_1_2V)
>> >> +
>> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL    (EXT_CSD_CARD_TYPE_SDR_200
>>  \
>> >> +                                     | EXT_CSD_CARD_TYPE_52
>>  \
>> >> +                                     | EXT_CSD_CARD_TYPE_26)
>> >> +
>> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_2V_ALL
>> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V     \
>> >> +                                     | EXT_CSD_CARD_TYPE_52
>>  \
>> >> +                                     | EXT_CSD_CARD_TYPE_26)
>> >> +
>> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_8V_ALL
>> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V     \
>> >> +                                     | EXT_CSD_CARD_TYPE_52
>>  \
>> >> +                                     | EXT_CSD_CARD_TYPE_26)
>> >> +
>> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V
>> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_DDR_1_8V
>> > \
>> >> +                                             | EXT_CSD_CARD_TYPE_52
>> > \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_26)
>> >> +
>> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V
>> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_DDR_1_8V
>> > \
>> >> +                                             | EXT_CSD_CARD_TYPE_52
>> > \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_26)
>> >> +
>> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V
>> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_DDR_1_2V
>> > \
>> >> +                                             | EXT_CSD_CARD_TYPE_52
>> > \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_26)
>> >> +
>> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V
>> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_DDR_1_2V
>> > \
>> >> +                                             | EXT_CSD_CARD_TYPE_52
>> > \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_26)
>> >> +
>> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52
>> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_DDR_52
>> > \
>> >> +                                             | EXT_CSD_CARD_TYPE_52
>> > \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_26)
>> >> +
>> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52
>> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_DDR_52
>> > \
>> >> +                                             | EXT_CSD_CARD_TYPE_52
>> > \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_26)
>> >> +
>> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V
>> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_DDR_1_8V
>> > \
>> >> +                                             | EXT_CSD_CARD_TYPE_52
>> > \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_26)
>> >> +
>> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V
>> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_DDR_1_2V
>> > \
>> >> +                                             | EXT_CSD_CARD_TYPE_52
>> > \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_26)
>> >> +
>> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52
>> (EXT_CSD_CARD_TYPE_SDR_200
>> >> \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_DDR_52
>> > \
>> >> +                                             | EXT_CSD_CARD_TYPE_52
>> > \
>> >> +                                             |
>> EXT_CSD_CARD_TYPE_26)
>> >>
>> >>  #define EXT_CSD_BUS_WIDTH_1  0       /* Card is in 1 bit mode */
>> >>  #define EXT_CSD_BUS_WIDTH_4  1       /* Card is in 4 bit mode */
>> >> diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
>> >> index e4b6935..d9a2222 100644
>> >> --- a/include/linux/mmc/sdhci.h
>> >> +++ b/include/linux/mmc/sdhci.h
>> >> @@ -121,6 +121,7 @@ struct sdhci_host {
>> >>  #define SDHCI_AUTO_CMD23     (1<<7)  /* Auto CMD23 support */
>> >>  #define SDHCI_PV_ENABLED     (1<<8)  /* Preset value enabled */
>> >>  #define SDHCI_SDIO_IRQ_ENABLED       (1<<9)  /* SDIO irq enabled */
>> >> +#define SDHCI_HS200_NEEDS_TUNING (1<<10)     /* HS200 needs tuning
>> */
>> >>
>> >>       unsigned int version;   /* SDHCI spec. version */
>> >>
>> >> --
>> >> 1.7.1
>> >>
>> >> --
>> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc"
>> in
>> >> the body of a message to majordomo@vger.kernel.org
>> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> >
>> > --
>> > To unsubscribe from this list: send the line "unsubscribe linux-mmc"
>> in
>> > the body of a message to majordomo@vger.kernel.org
>> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> >
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
Subhash Jadavani Dec. 1, 2011, 6:32 p.m. UTC | #5
> -----Original Message-----
> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
> owner@vger.kernel.org] On Behalf Of Girish K S
> Sent: Thursday, December 01, 2011 7:48 PM
> To: Subhash Jadavani
> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
> soc@vger.kernel.org; Chris Ball
> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
> 
> On 1 December 2011 16:27, Subhash Jadavani <subhashj@codeaurora.org>
> wrote:
> >
> >
> >> -----Original Message-----
> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
> >> owner@vger.kernel.org] On Behalf Of Girish K S
> >> Sent: Thursday, December 01, 2011 3:58 PM
> >> To: Subhash Jadavani
> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
> >> soc@vger.kernel.org; Chris Ball
> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
> >>
> >> On 1 December 2011 15:33, Subhash Jadavani <subhashj@codeaurora.org>
> >> wrote:
> >> > Hi Girish,
> >> >
> >> >> -----Original Message-----
> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
> >> >> Sent: Wednesday, November 30, 2011 2:24 PM
> >> >> To: linux-mmc@vger.kernel.org
> >> >> Cc: patches@linaro.org; linux-samsung-soc@vger.kernel.org;
> >> >> subhashj@codeaurora.org; Girish K S; Chris Ball
> >> >> Subject: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
> >> >>
> >> >> This patch adds the support of the HS200 bus speed for eMMC 4.5
> >> >> devices.
> >> >> The eMMC 4.5 devices have support for 200MHz bus speed.The mmc
> core
> >> and
> >> >> host modules have been touched to add support for this module.
> >> >>
> >> >> It is necessary to know the card type in the sdhci.c file to add
> >> >> support
> >> >> for eMMC tuning function. So card.h file is included to import
> the
> >> card
> >> >> data structure.
> >> >>
> >> >> cc: Chris Ball <cjb@laptop.org>
> >> >> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
> >> >> ---
> >> >> Changes in v5:
> >> >>       Reduced the case statements for better code readability.
> >> Removed
> >> >>       unused macro definitions. Modified the tuning function
> >> prototype
> >> >>       and definition to support tuning for both SD and eMMC
> cards.
> >> >> Changes in v4:
> >> >>       Rebased onto chris-mmc/mmc-next branch. This patch is
> >> >> successfully
> >> >>       applied on commit with id
> >> >> de022ed3fdc14808299b2fa66dbb1ed5ab921912.
> >> >> Changes in v3:
> >> >>       In the previous commits of chris-mmc/mmc-next branch, the
> >> patch
> >> >> with
> >> >>       commit id (c0f22a2c92e357e7cb3988b0b13034d70b7461f9)
> defines
> >> >> caps2 for
> >> >>       more capabilities. This patch version deletes the member
> >> >> ext_caps(created
> >> >>       in my earlier patch) from struct mmc_host and reuses
> already
> >> >> accepted
> >> >>       caps2 member.
> >> >> Changes in v2:
> >> >>       Rebased to latest chris-mmc/mmc-next branch. Resolved
> >> indentation
> >> >>       problems identified in review. This patch has to be applied
> >> >> before
> >> >>       the patch released for modifying the printk messages.
> >> >> Changes in v1:
> >> >>       Case statements in switch that produce same result have
> >> >>       been combined to reduce repeated assignments.
> >> >>       patch recreated after rebase to chris balls mmc-next
> branch.
> >> >>
> >> >>  drivers/mmc/core/bus.c    |    3 +-
> >> >>  drivers/mmc/core/mmc.c    |   77
> >> >> ++++++++++++++++++++++++++++++++++++++++----
> >> >>  drivers/mmc/core/sd.c     |    3 +-
> >> >>  drivers/mmc/core/sdio.c   |    4 ++-
> >> >>  drivers/mmc/host/sdhci.c  |   38 +++++++++++++++++-----
> >> >>  include/linux/mmc/card.h  |    3 ++
> >> >>  include/linux/mmc/host.h  |   11 ++++++-
> >> >>  include/linux/mmc/mmc.h   |   66
> >> >> ++++++++++++++++++++++++++++++++++++++-
> >> >>  include/linux/mmc/sdhci.h |    1 +
> >> >>  9 files changed, 185 insertions(+), 21 deletions(-)
> >> >>
> >> >> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> >> >> index 5639fdf..83c9f8d 100644
> >> >> --- a/drivers/mmc/core/bus.c
> >> >> +++ b/drivers/mmc/core/bus.c
> >> >> @@ -301,10 +301,11 @@ int mmc_add_card(struct mmc_card *card)
> >> >>                       mmc_card_ddr_mode(card) ? "DDR " : "",
> >> >>                       type);
> >> >>       } else {
> >> >> -             printk(KERN_INFO "%s: new %s%s%s card at address
> >> %04x\n",
> >> >> +             pr_info("%s: new %s%s%s%s card at address %04x\n",
> >> >>                       mmc_hostname(card->host),
> >> >>                       mmc_card_uhs(card) ? "ultra high speed " :
> >> >>                       (mmc_card_highspeed(card) ? "high speed " :
> >> ""),
> >> >> +                     (mmc_card_hs200(card) ? "HS200 " : ""),
> >> >>                       mmc_card_ddr_mode(card) ? "DDR " : "",
> >> >>                       type, card->rca);
> >> >>       }
> >> >> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> >> >> index a1223bd..f4124d6 100644
> >> >> --- a/drivers/mmc/core/mmc.c
> >> >> +++ b/drivers/mmc/core/mmc.c
> >> >> @@ -285,6 +285,27 @@ static int mmc_read_ext_csd(struct mmc_card
> >> *card,
> >> >> u8 *ext_csd)
> >> >>       }
> >> >>       card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
> >> >>       switch (ext_csd[EXT_CSD_CARD_TYPE] &
> EXT_CSD_CARD_TYPE_MASK) {
> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL:
> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
> >> >> +             card->ext_csd.card_type =
> EXT_CSD_CARD_TYPE_SDR_200;
> >> >> +             break;
> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
> >> >> +             card->ext_csd.card_type =
> EXT_CSD_CARD_TYPE_SDR_1_2V;
> >> >> +             break;
> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
> >> >> +             card->ext_csd.card_type =
> EXT_CSD_CARD_TYPE_SDR_1_8V;
> >> >> +             break;
> >> >>       case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
> >> >>            EXT_CSD_CARD_TYPE_26:
> >> >>               card->ext_csd.hs_max_dtr = 52000000;
> >> >> @@ -699,6 +720,7 @@ static int mmc_init_card(struct mmc_host
> *host,
> >> u32
> >> >> ocr,
> >> >>  {
> >> >>       struct mmc_card *card;
> >> >>       int err, ddr = 0;
> >> >> +     int hs_sdr = 0;
> >> >>       u32 cid[4];
> >> >>       unsigned int max_dtr;
> >> >>       u32 rocr;
> >> >> @@ -894,11 +916,16 @@ static int mmc_init_card(struct mmc_host
> >> *host,
> >> >> u32 ocr,
> >> >>       /*
> >> >>        * Activate high speed (if supported)
> >> >>        */
> >> >> -     if ((card->ext_csd.hs_max_dtr != 0) &&
> >> >> -             (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
> >> >> -             err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >> -                              EXT_CSD_HS_TIMING, 1,
> >> >> -                              card->ext_csd.generic_cmd6_time);
> >> >> +     if (card->ext_csd.hs_max_dtr != 0) {
> >> >> +             err = 0;
> >> >> +             if ((card->ext_csd.hs_max_dtr > 52000000) &&
> >> >> +                 (host->caps2 & MMC_CAP2_HS200))
> >> >> +                     err = mmc_switch(card,
> EXT_CSD_CMD_SET_NORMAL,
> >> >> +                                      EXT_CSD_HS_TIMING, 2, 0);
> >> >> +             else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
> >> >> +                     err = mmc_switch(card,
> EXT_CSD_CMD_SET_NORMAL,
> >> >> +                                      EXT_CSD_HS_TIMING, 1, 0);
> >> >> +
> >> >>               if (err && err != -EBADMSG)
> >> >>                       goto free_card;
> >> >>
> >> >> @@ -907,7 +934,11 @@ static int mmc_init_card(struct mmc_host
> *host,
> >> >> u32 ocr,
> >> >>                              mmc_hostname(card->host));
> >> >>                       err = 0;
> >> >>               } else {
> >> >> -                     mmc_card_set_highspeed(card);
> >> >> +                     if ((card->ext_csd.hs_max_dtr > 52000000)
> &&
> >> >> +                         (host->caps2 & MMC_CAP2_HS200))
> >> >> +                             mmc_card_set_hs200(card);
> >> >> +                     else
> >> >> +                             mmc_card_set_highspeed(card);
> >> >>                       mmc_set_timing(card->host,
> MMC_TIMING_MMC_HS);
> >> >
> >> > MMC_TIMING_MMC_HS200 is defined but still not used.
> >> >
> >> > So I guess it should be like this ::
> >> >  +                      if ((card->ext_csd.hs_max_dtr > 52000000)
> &&
> >> >  +                          (host->caps2 & MMC_CAP2_HS200)) {
> >> >  +                              mmc_card_set_hs200(card);
> >> >  +                      mmc_set_timing(card->host,
> >> MMC_TIMING_MMC_HS200)
> >> >  +                      } else {
> >> >  +                              mmc_card_set_highspeed(card);
> >> >  +                              mmc_set_timing(card->host,
> >> > MMC_TIMING_MMC_HS)
> >> >  +                      }
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >>               }
> >> >>       }
> >> >> @@ -933,7 +964,7 @@ static int mmc_init_card(struct mmc_host
> *host,
> >> u32
> >> >> ocr,
> >> >>        */
> >> >>       max_dtr = (unsigned int)-1;
> >> >>
> >> >> -     if (mmc_card_highspeed(card)) {
> >> >> +     if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
> >> >>               if (max_dtr > card->ext_csd.hs_max_dtr)
> >> >>                       max_dtr = card->ext_csd.hs_max_dtr;
> >> >>       } else if (max_dtr > card->csd.max_dtr) {
> >> >> @@ -959,6 +990,18 @@ static int mmc_init_card(struct mmc_host
> *host,
> >> >> u32 ocr,
> >> >>       }
> >> >>
> >> >>       /*
> >> >> +      * Indicate HS200 SDR mode (if supported).
> >> >> +      */
> >> >> +     if (mmc_card_hs200(card)) {
> >> >> +             if ((card->ext_csd.card_type &
> >> EXT_CSD_CARD_TYPE_SDR_1_8V)
> >> >> +                     && (host->caps2 & MMC_CAP2_HS200_1_8V_SDR))
> >> >> +                             hs_sdr = MMC_1_8V_SDR_MODE;
> >> >> +             else if ((card->ext_csd.card_type &
> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
> >> >> +                     && (host->caps2 & MMC_CAP2_HS200_1_2V_SDR))
> >> >> +                             hs_sdr = MMC_1_2V_SDR_MODE;
> >> >> +     }
> >> >> +
> >> >> +     /*
> >> >>        * Activate wide bus and DDR (if supported).
> >> >>        */
> >> >>       if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
> >> >> @@ -998,6 +1041,17 @@ static int mmc_init_card(struct mmc_host
> >> *host,
> >> >> u32 ocr,
> >> >>                       if (!err) {
> >> >>                               mmc_set_bus_width(card->host,
> >> bus_width);
> >> >>
> >> >> +                             if ((host->caps2 & MMC_CAP2_HS200)
> &&
> >> >> +                                 card->host->ops-
> >execute_tuning)
> >> >> +                                     err = card->host->ops-> \
> >> >> +                                           execute_tuning(card-
> >> >host,
> >> >> +
> >> > MMC_SEND_TUNING_BLOCK_HS200);
> >> >
> >> >
> >> > execute_tuning should be done right after the timing is changed to
> >> HS200 and
> >> > clock rate is changed to 200Mhz. This is not the correct sequence
> to
> >> call
> >> > the execute_tuning().
> >> > As told earlier, It is mentioned in the spec that tuning should be
> >> executed after change of buswidth (mandatory). Also it mentions that
> >> "The host may invoke the HS200 tuning sequence, by sending CMD21 to
> the
> >> device". It means that
> >>  after setting the HS200 mode, Changing to freq > 52Mhz and changing
> >> the bus width tuning can be executed anytime to identify the
> sampling
> >> point to read.(By anytime i mean before actual block read
> Operation).
> >> Can you please point me to the place in the spec where it specifies
> >> tuning should be done immediately after freq change (may be i missed
> >> to read it).
> >
> >
> > Ok. let me ask you this. Why do we run the execute_tuning()? It's to
> tune
> > the sampling clock generator of host controller before you start any
> read
> > operation (on command line or data line) from card. If you don't tune
> the
> > sampling clock generator before the read operation (after changing
> the
> > timing to HS200 and clock rate to 200mhz), you can't be sure that
> read
> > operation from card will be completed without errors. You may get the
> data /
> > cmd response CRC errors. At least this will surely fail on our MSM
> SDCC host
> > controller. That's what we had faced with SD3.0 UHS-I tuning as well
> as
> > mentioned in http://www.spinics.net/lists/linux-arm-
> msm/msg03867.html.

> > this tuning is done before any read opration for the best bus width
> supported.
Agreed. But can we be sure that "command response" for bus width change via
CMD6, will not have any command CRC failures if tuning is not done? 

> ps:Chris need your comment on this
> >
> >> >> +
> >> >> +                             if (err) {
> >> >> +                                     pr_warning("tuning
> execution
> >> > failed\n");
> >> >> +                                     continue;
> >> >> +                             }
> >> >> +
> >> >>                               /*
> >> >>                                * If controller can't handle bus
> >> width
> >> > test,
> >> >>                                * compare ext_csd previously read
> in
> >> 1 bit
> >> >> mode
> >> >> @@ -1056,6 +1110,15 @@ static int mmc_init_card(struct mmc_host
> >> *host,
> >> >> u32 ocr,
> >> >>                       mmc_card_set_ddr_mode(card);
> >> >>                       mmc_set_timing(card->host,
> >> MMC_TIMING_UHS_DDR50);
> >> >>                       mmc_set_bus_width(card->host, bus_width);
> >> >> +             } else if (hs_sdr) {
> >> >> +                     if (hs_sdr == EXT_CSD_CARD_TYPE_SDR_1_2V) {
> >> >> +                             err = mmc_set_signal_voltage(host,
> >> >> +                                     MMC_SIGNAL_VOLTAGE_120, 0);
> >> >> +                             if (err)
> >> >> +                                     goto err;
> >> >> +                     }
> >> >> +                     mmc_set_timing(card->host,
> MMC_TIMING_MMC_HS);
> >> >> +                     mmc_set_bus_width(card->host, bus_width);
> >> >>               }
> >> >>       }
> >> >>
> >> >> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> >> >> index 1d5a3bd..c1d3ee3 100644
> >> >> --- a/drivers/mmc/core/sd.c
> >> >> +++ b/drivers/mmc/core/sd.c
> >> >> @@ -660,7 +660,8 @@ static int mmc_sd_init_uhs_card(struct
> mmc_card
> >> >> *card)
> >> >>
> >> >>       /* SPI mode doesn't define CMD19 */
> >> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
> >> >> >execute_tuning)
> >> >> -             err = card->host->ops->execute_tuning(card->host);
> >> >> +             err = card->host->ops->execute_tuning(card->host,
> >>   \
> >> >> +
> >> > MMC_SEND_TUNING_BLOCK);
> >> >>
> >> >>  out:
> >> >>       kfree(status);
> >> >> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
> >> >> index 8c04f7f..8ef8817 100644
> >> >> --- a/drivers/mmc/core/sdio.c
> >> >> +++ b/drivers/mmc/core/sdio.c
> >> >> @@ -14,6 +14,7 @@
> >> >>
> >> >>  #include <linux/mmc/host.h>
> >> >>  #include <linux/mmc/card.h>
> >> >> +#include <linux/mmc/mmc.h>
> >> >>  #include <linux/mmc/sdio.h>
> >> >>  #include <linux/mmc/sdio_func.h>
> >> >>  #include <linux/mmc/sdio_ids.h>
> >> >> @@ -556,7 +557,8 @@ static int mmc_sdio_init_uhs_card(struct
> >> mmc_card
> >> >> *card)
> >> >>
> >> >>       /* Initialize and start re-tuning timer */
> >> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
> >> >> >execute_tuning)
> >> >> -             err = card->host->ops->execute_tuning(card->host);
> >> >> +             err = card->host->ops->execute_tuning(card->host,
> >> >> +
> >> > MMC_SEND_TUNING_BLOCK);
> >> >>
> >> >>  out:
> >> >>
> >> >> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> >> >> index a7c2311..13d74bb 100644
> >> >> --- a/drivers/mmc/host/sdhci.c
> >> >> +++ b/drivers/mmc/host/sdhci.c
> >> >> @@ -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
> >> >> @@ -1016,7 +1016,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
> */
> >> >> @@ -1673,7 +1674,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;
> >> >> @@ -1694,10 +1695,13 @@ static int sdhci_execute_tuning(struct
> >> mmc_host
> >> >> *mmc)
> >> >>        * Host Controller needs tuning only in case of SDR104 mode
> >> >>        * and for SDR50 mode when Use Tuning for SDR50 is set in
> >> >>        * Capabilities register.
> >> >> +      * If the Host Controller supports the HS200 mode then
> tuning
> >> >> +      * function has to be executed.
> >> >>        */
> >> >>       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)))
> >> >> +         (host->flags & SDHCI_SDR50_NEEDS_TUNING)) ||
> >> >> +         (host->flags & SDHCI_HS200_NEEDS_TUNING))
> >> >>               ctrl |= SDHCI_CTRL_EXEC_TUNING;
> >> >>       else {
> >> >>               spin_unlock(&host->lock);
> >> >> @@ -1733,7 +1737,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;
> >> >> @@ -1748,7 +1752,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.
> >> >> @@ -2131,12 +2145,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;
> >> >> @@ -2741,6 +2757,10 @@ int sdhci_add_host(struct sdhci_host
> *host)
> >> >>       if (caps[1] & SDHCI_USE_SDR50_TUNING)
> >> >>               host->flags |= SDHCI_SDR50_NEEDS_TUNING;
> >> >>
> >> >> +     /* Does the host needs 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;
> >> >> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> >> >> index 534974c..e76f649 100644
> >> >> --- a/include/linux/mmc/card.h
> >> >> +++ b/include/linux/mmc/card.h
> >> >> @@ -209,6 +209,7 @@ struct mmc_card {
> >> >>  #define MMC_STATE_HIGHSPEED_DDR (1<<4)               /* card is
> in
> >> high
> >> >> speed mode */
> >> >>  #define MMC_STATE_ULTRAHIGHSPEED (1<<5)              /* card is
> in
> >> ultra
> >> >> high speed mode */
> >> >>  #define MMC_CARD_SDXC                (1<<6)          /* card is
> >> SDXC */
> >> >> +#define MMC_STATE_HIGHSPEED_200      (1<<7)  /* card is in HS200
> >> >> mode */
> >> >>       unsigned int            quirks;         /* card quirks */
> >> >>  #define MMC_QUIRK_LENIENT_FN0        (1<<0)          /* allow
> SDIO
> >> FN0
> >> >> writes outside of the VS CCCR range */
> >> >>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func-
> >> >> >cur_blksize */
> >> >> @@ -365,6 +366,7 @@ static inline void __maybe_unused
> >> >> remove_quirk(struct mmc_card *card, int data)
> >> >>  #define mmc_card_present(c)  ((c)->state & MMC_STATE_PRESENT)
> >> >>  #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
> >> >>  #define mmc_card_highspeed(c)        ((c)->state &
> >> MMC_STATE_HIGHSPEED)
> >> >> +#define mmc_card_hs200(c)    ((c)->state &
> MMC_STATE_HIGHSPEED_200)
> >> >>  #define mmc_card_blockaddr(c)        ((c)->state &
> >> MMC_STATE_BLOCKADDR)
> >> >>  #define mmc_card_ddr_mode(c) ((c)->state &
> MMC_STATE_HIGHSPEED_DDR)
> >> >>  #define mmc_card_uhs(c)              ((c)->state &
> >> >> MMC_STATE_ULTRAHIGHSPEED)
> >> >> @@ -374,6 +376,7 @@ static inline void __maybe_unused
> >> >> remove_quirk(struct mmc_card *card, int data)
> >> >>  #define mmc_card_set_present(c)      ((c)->state |=
> >> MMC_STATE_PRESENT)
> >> >>  #define mmc_card_set_readonly(c) ((c)->state |=
> MMC_STATE_READONLY)
> >> >>  #define mmc_card_set_highspeed(c) ((c)->state |=
> >> MMC_STATE_HIGHSPEED)
> >> >> +#define mmc_card_set_hs200(c)        ((c)->state |=
> >> >> MMC_STATE_HIGHSPEED_200)
> >> >>  #define mmc_card_set_blockaddr(c) ((c)->state |=
> >> MMC_STATE_BLOCKADDR)
> >> >>  #define mmc_card_set_ddr_mode(c) ((c)->state |=
> >> >> MMC_STATE_HIGHSPEED_DDR)
> >> >>  #define mmc_card_set_uhs(c) ((c)->state |=
> >> MMC_STATE_ULTRAHIGHSPEED)
> >> >> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> >> >> index 706f722..5eac57a 100644
> >> >> --- a/include/linux/mmc/host.h
> >> >> +++ b/include/linux/mmc/host.h
> >> >> @@ -50,6 +50,7 @@ struct mmc_ios {
> >> >>
> >> >>  #define MMC_TIMING_LEGACY    0
> >> >>  #define MMC_TIMING_MMC_HS    1
> >> >> +#define MMC_TIMING_MMC_HS200 2
> >> >>  #define MMC_TIMING_SD_HS     2
> >> >>  #define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY
> >> >>  #define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS
> >> >> @@ -60,6 +61,8 @@ struct mmc_ios {
> >> >>  #define MMC_SDR_MODE         0
> >> >>  #define MMC_1_2V_DDR_MODE    1
> >> >>  #define MMC_1_8V_DDR_MODE    2
> >> >> +#define MMC_1_2V_SDR_MODE    3
> >> >> +#define MMC_1_8V_SDR_MODE    4
> >> >>
> >> >>       unsigned char   signal_voltage;         /* signalling
> voltage
> >> >> (1.8V or 3.3V) */
> >> >>
> >> >> @@ -148,7 +151,9 @@ struct mmc_host_ops {
> >> >>       void    (*init_card)(struct mmc_host *host, struct mmc_card
> >> *card);
> >> >>
> >> >>       int     (*start_signal_voltage_switch)(struct mmc_host
> *host,
> >> >> struct mmc_ios *ios);
> >> >> -     int     (*execute_tuning)(struct mmc_host *host);
> >> >> +
> >> >> +     /* The tuning command opcode value is different for SD and
> >> eMMC
> >> >> cards */
> >> >> +     int     (*execute_tuning)(struct mmc_host *host, u32
> opcode);
> >> >>       void    (*enable_preset_value)(struct mmc_host *host, bool
> >> enable);
> >> >>       int     (*select_drive_strength)(unsigned int max_dtr, int
> >> >> host_drv, int card_drv);
> >> >>       void    (*hw_reset)(struct mmc_host *host);
> >> >> @@ -242,6 +247,10 @@ struct mmc_host {
> >> >>  #define MMC_CAP2_CACHE_CTRL  (1 << 1)        /* Allow cache
> control
> >> */
> >> >>  #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)    /* Notify poweroff
> >> >> supported */
> >> >>  #define MMC_CAP2_NO_MULTI_READ       (1 << 3)        /*
> Multiblock
> >> reads
> >> >> don't work */
> >> >> +#define MMC_CAP2_HS200_1_8V_SDR      (1 << 4)        /* can
> support
> >> */
> >> >> +#define MMC_CAP2_HS200_1_2V_SDR      (1 << 5)        /* can
> support
> >> */
> >> >> +#define MMC_CAP2_HS200               (MMC_CAP2_HS200_1_8V_SDR |
> \
> >> >> +                              MMC_CAP2_HS200_1_2V_SDR)
> >> >>
> >> >>       mmc_pm_flag_t           pm_caps;        /* supported pm
> >> features */
> >> >>       unsigned int        power_notify_type;
> >> >> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> >> >> index 0e71356..7996272 100644
> >> >> --- a/include/linux/mmc/mmc.h
> >> >> +++ b/include/linux/mmc/mmc.h
> >> >> @@ -51,6 +51,7 @@
> >> >>  #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr
> R1
> >> >> */
> >> >>  #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr
> R1
> >> >> */
> >> >>  #define MMC_SEND_TUNING_BLOCK    19   /* adtc
>  R1
> >> >> */
> >> >> +#define MMC_SEND_TUNING_BLOCK_HS200  21      /* adtc R1  */
> >> >>
> >> >>    /* class 3 */
> >> >>  #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr
> R1
> >> >> */
> >> >> @@ -333,13 +334,76 @@ struct _mmc_csd {
> >> >>
> >> >>  #define EXT_CSD_CARD_TYPE_26 (1<<0)  /* Card can run at 26MHz */
> >> >>  #define EXT_CSD_CARD_TYPE_52 (1<<1)  /* Card can run at 52MHz */
> >> >> -#define EXT_CSD_CARD_TYPE_MASK       0xF     /* Mask out
> reserved
> >> bits */
> >> >> +#define EXT_CSD_CARD_TYPE_MASK       0x3F    /* Mask out
> reserved
> >> bits */
> >> >>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at
> >> 52MHz
> >> >> */
> >> >>                                            /* DDR mode @1.8V or
> 3V
> >> I/O */
> >> >>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at
> >> 52MHz
> >> >> */
> >> >>                                            /* DDR mode @1.2V I/O
> */
> >> >>  #define EXT_CSD_CARD_TYPE_DDR_52
> (EXT_CSD_CARD_TYPE_DDR_1_8V
> >>  \
> >> >>                                       |
> EXT_CSD_CARD_TYPE_DDR_1_2V)
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V   (1<<4)  /* Card can run at
> >> >> 200MHz */
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V   (1<<5)  /* Card can run at
> >> >> 200MHz */
> >> >> +                                             /* SDR mode @1.2V
> I/O
> >> */
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_200    (EXT_CSD_CARD_TYPE_SDR_1_8V
> >>   \
> >> >> +                                     |
> EXT_CSD_CARD_TYPE_SDR_1_2V)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL    (EXT_CSD_CARD_TYPE_SDR_200
> >>  \
> >> >> +                                     | EXT_CSD_CARD_TYPE_52
> >>  \
> >> >> +                                     | EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_2V_ALL
> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V     \
> >> >> +                                     | EXT_CSD_CARD_TYPE_52
> >>  \
> >> >> +                                     | EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_8V_ALL
> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V     \
> >> >> +                                     | EXT_CSD_CARD_TYPE_52
> >>  \
> >> >> +                                     | EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V
> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_DDR_1_8V
> >> > \
> >> >> +                                             |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V
> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_DDR_1_8V
> >> > \
> >> >> +                                             |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V
> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_DDR_1_2V
> >> > \
> >> >> +                                             |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V
> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_DDR_1_2V
> >> > \
> >> >> +                                             |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52
> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_DDR_52
> >> > \
> >> >> +                                             |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52
> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_DDR_52
> >> > \
> >> >> +                                             |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V
> >> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_DDR_1_8V
> >> > \
> >> >> +                                             |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V
> >> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_DDR_1_2V
> >> > \
> >> >> +                                             |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52
> >> (EXT_CSD_CARD_TYPE_SDR_200
> >> >> \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_DDR_52
> >> > \
> >> >> +                                             |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_26)
> >> >>
> >> >>  #define EXT_CSD_BUS_WIDTH_1  0       /* Card is in 1 bit mode */
> >> >>  #define EXT_CSD_BUS_WIDTH_4  1       /* Card is in 4 bit mode */
> >> >> diff --git a/include/linux/mmc/sdhci.h
> b/include/linux/mmc/sdhci.h
> >> >> index e4b6935..d9a2222 100644
> >> >> --- a/include/linux/mmc/sdhci.h
> >> >> +++ b/include/linux/mmc/sdhci.h
> >> >> @@ -121,6 +121,7 @@ struct sdhci_host {
> >> >>  #define SDHCI_AUTO_CMD23     (1<<7)  /* Auto CMD23 support */
> >> >>  #define SDHCI_PV_ENABLED     (1<<8)  /* Preset value enabled */
> >> >>  #define SDHCI_SDIO_IRQ_ENABLED       (1<<9)  /* SDIO irq enabled
> */
> >> >> +#define SDHCI_HS200_NEEDS_TUNING (1<<10)     /* HS200 needs
> tuning
> >> */
> >> >>
> >> >>       unsigned int version;   /* SDHCI spec. version */
> >> >>
> >> >> --
> >> >> 1.7.1
> >> >>
> >> >> --
> >> >> To unsubscribe from this list: send the line "unsubscribe linux-
> mmc"
> >> in
> >> >> the body of a message to majordomo@vger.kernel.org
> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
> info.html
> >> >
> >> > --
> >> > To unsubscribe from this list: send the line "unsubscribe linux-
> mmc"
> >> in
> >> > the body of a message to majordomo@vger.kernel.org
> >> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >> >
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc"
> in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Girish K S Dec. 2, 2011, 11:37 a.m. UTC | #6
On 2 December 2011 00:02, Subhash Jadavani <subhashj@codeaurora.org> wrote:
>
>
>> -----Original Message-----
>> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>> owner@vger.kernel.org] On Behalf Of Girish K S
>> Sent: Thursday, December 01, 2011 7:48 PM
>> To: Subhash Jadavani
>> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>> soc@vger.kernel.org; Chris Ball
>> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>>
>> On 1 December 2011 16:27, Subhash Jadavani <subhashj@codeaurora.org>
>> wrote:
>> >
>> >
>> >> -----Original Message-----
>> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>> >> owner@vger.kernel.org] On Behalf Of Girish K S
>> >> Sent: Thursday, December 01, 2011 3:58 PM
>> >> To: Subhash Jadavani
>> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>> >> soc@vger.kernel.org; Chris Ball
>> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>> >>
>> >> On 1 December 2011 15:33, Subhash Jadavani <subhashj@codeaurora.org>
>> >> wrote:
>> >> > Hi Girish,
>> >> >
>> >> >> -----Original Message-----
>> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
>> >> >> Sent: Wednesday, November 30, 2011 2:24 PM
>> >> >> To: linux-mmc@vger.kernel.org
>> >> >> Cc: patches@linaro.org; linux-samsung-soc@vger.kernel.org;
>> >> >> subhashj@codeaurora.org; Girish K S; Chris Ball
>> >> >> Subject: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>> >> >>
>> >> >> This patch adds the support of the HS200 bus speed for eMMC 4.5
>> >> >> devices.
>> >> >> The eMMC 4.5 devices have support for 200MHz bus speed.The mmc
>> core
>> >> and
>> >> >> host modules have been touched to add support for this module.
>> >> >>
>> >> >> It is necessary to know the card type in the sdhci.c file to add
>> >> >> support
>> >> >> for eMMC tuning function. So card.h file is included to import
>> the
>> >> card
>> >> >> data structure.
>> >> >>
>> >> >> cc: Chris Ball <cjb@laptop.org>
>> >> >> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
>> >> >> ---
>> >> >> Changes in v5:
>> >> >>       Reduced the case statements for better code readability.
>> >> Removed
>> >> >>       unused macro definitions. Modified the tuning function
>> >> prototype
>> >> >>       and definition to support tuning for both SD and eMMC
>> cards.
>> >> >> Changes in v4:
>> >> >>       Rebased onto chris-mmc/mmc-next branch. This patch is
>> >> >> successfully
>> >> >>       applied on commit with id
>> >> >> de022ed3fdc14808299b2fa66dbb1ed5ab921912.
>> >> >> Changes in v3:
>> >> >>       In the previous commits of chris-mmc/mmc-next branch, the
>> >> patch
>> >> >> with
>> >> >>       commit id (c0f22a2c92e357e7cb3988b0b13034d70b7461f9)
>> defines
>> >> >> caps2 for
>> >> >>       more capabilities. This patch version deletes the member
>> >> >> ext_caps(created
>> >> >>       in my earlier patch) from struct mmc_host and reuses
>> already
>> >> >> accepted
>> >> >>       caps2 member.
>> >> >> Changes in v2:
>> >> >>       Rebased to latest chris-mmc/mmc-next branch. Resolved
>> >> indentation
>> >> >>       problems identified in review. This patch has to be applied
>> >> >> before
>> >> >>       the patch released for modifying the printk messages.
>> >> >> Changes in v1:
>> >> >>       Case statements in switch that produce same result have
>> >> >>       been combined to reduce repeated assignments.
>> >> >>       patch recreated after rebase to chris balls mmc-next
>> branch.
>> >> >>
>> >> >>  drivers/mmc/core/bus.c    |    3 +-
>> >> >>  drivers/mmc/core/mmc.c    |   77
>> >> >> ++++++++++++++++++++++++++++++++++++++++----
>> >> >>  drivers/mmc/core/sd.c     |    3 +-
>> >> >>  drivers/mmc/core/sdio.c   |    4 ++-
>> >> >>  drivers/mmc/host/sdhci.c  |   38 +++++++++++++++++-----
>> >> >>  include/linux/mmc/card.h  |    3 ++
>> >> >>  include/linux/mmc/host.h  |   11 ++++++-
>> >> >>  include/linux/mmc/mmc.h   |   66
>> >> >> ++++++++++++++++++++++++++++++++++++++-
>> >> >>  include/linux/mmc/sdhci.h |    1 +
>> >> >>  9 files changed, 185 insertions(+), 21 deletions(-)
>> >> >>
>> >> >> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> >> >> index 5639fdf..83c9f8d 100644
>> >> >> --- a/drivers/mmc/core/bus.c
>> >> >> +++ b/drivers/mmc/core/bus.c
>> >> >> @@ -301,10 +301,11 @@ int mmc_add_card(struct mmc_card *card)
>> >> >>                       mmc_card_ddr_mode(card) ? "DDR " : "",
>> >> >>                       type);
>> >> >>       } else {
>> >> >> -             printk(KERN_INFO "%s: new %s%s%s card at address
>> >> %04x\n",
>> >> >> +             pr_info("%s: new %s%s%s%s card at address %04x\n",
>> >> >>                       mmc_hostname(card->host),
>> >> >>                       mmc_card_uhs(card) ? "ultra high speed " :
>> >> >>                       (mmc_card_highspeed(card) ? "high speed " :
>> >> ""),
>> >> >> +                     (mmc_card_hs200(card) ? "HS200 " : ""),
>> >> >>                       mmc_card_ddr_mode(card) ? "DDR " : "",
>> >> >>                       type, card->rca);
>> >> >>       }
>> >> >> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> >> >> index a1223bd..f4124d6 100644
>> >> >> --- a/drivers/mmc/core/mmc.c
>> >> >> +++ b/drivers/mmc/core/mmc.c
>> >> >> @@ -285,6 +285,27 @@ static int mmc_read_ext_csd(struct mmc_card
>> >> *card,
>> >> >> u8 *ext_csd)
>> >> >>       }
>> >> >>       card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>> >> >>       switch (ext_csd[EXT_CSD_CARD_TYPE] &
>> EXT_CSD_CARD_TYPE_MASK) {
>> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL:
>> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
>> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
>> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
>> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
>> >> >> +             card->ext_csd.card_type =
>> EXT_CSD_CARD_TYPE_SDR_200;
>> >> >> +             break;
>> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
>> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
>> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
>> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
>> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
>> >> >> +             card->ext_csd.card_type =
>> EXT_CSD_CARD_TYPE_SDR_1_2V;
>> >> >> +             break;
>> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
>> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
>> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
>> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
>> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
>> >> >> +             card->ext_csd.card_type =
>> EXT_CSD_CARD_TYPE_SDR_1_8V;
>> >> >> +             break;
>> >> >>       case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
>> >> >>            EXT_CSD_CARD_TYPE_26:
>> >> >>               card->ext_csd.hs_max_dtr = 52000000;
>> >> >> @@ -699,6 +720,7 @@ static int mmc_init_card(struct mmc_host
>> *host,
>> >> u32
>> >> >> ocr,
>> >> >>  {
>> >> >>       struct mmc_card *card;
>> >> >>       int err, ddr = 0;
>> >> >> +     int hs_sdr = 0;
>> >> >>       u32 cid[4];
>> >> >>       unsigned int max_dtr;
>> >> >>       u32 rocr;
>> >> >> @@ -894,11 +916,16 @@ static int mmc_init_card(struct mmc_host
>> >> *host,
>> >> >> u32 ocr,
>> >> >>       /*
>> >> >>        * Activate high speed (if supported)
>> >> >>        */
>> >> >> -     if ((card->ext_csd.hs_max_dtr != 0) &&
>> >> >> -             (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
>> >> >> -             err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> >> -                              EXT_CSD_HS_TIMING, 1,
>> >> >> -                              card->ext_csd.generic_cmd6_time);
>> >> >> +     if (card->ext_csd.hs_max_dtr != 0) {
>> >> >> +             err = 0;
>> >> >> +             if ((card->ext_csd.hs_max_dtr > 52000000) &&
>> >> >> +                 (host->caps2 & MMC_CAP2_HS200))
>> >> >> +                     err = mmc_switch(card,
>> EXT_CSD_CMD_SET_NORMAL,
>> >> >> +                                      EXT_CSD_HS_TIMING, 2, 0);
>> >> >> +             else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
>> >> >> +                     err = mmc_switch(card,
>> EXT_CSD_CMD_SET_NORMAL,
>> >> >> +                                      EXT_CSD_HS_TIMING, 1, 0);
>> >> >> +
>> >> >>               if (err && err != -EBADMSG)
>> >> >>                       goto free_card;
>> >> >>
>> >> >> @@ -907,7 +934,11 @@ static int mmc_init_card(struct mmc_host
>> *host,
>> >> >> u32 ocr,
>> >> >>                              mmc_hostname(card->host));
>> >> >>                       err = 0;
>> >> >>               } else {
>> >> >> -                     mmc_card_set_highspeed(card);
>> >> >> +                     if ((card->ext_csd.hs_max_dtr > 52000000)
>> &&
>> >> >> +                         (host->caps2 & MMC_CAP2_HS200))
>> >> >> +                             mmc_card_set_hs200(card);
>> >> >> +                     else
>> >> >> +                             mmc_card_set_highspeed(card);
>> >> >>                       mmc_set_timing(card->host,
>> MMC_TIMING_MMC_HS);
>> >> >
>> >> > MMC_TIMING_MMC_HS200 is defined but still not used.
>> >> >
>> >> > So I guess it should be like this ::
>> >> >  +                      if ((card->ext_csd.hs_max_dtr > 52000000)
>> &&
>> >> >  +                          (host->caps2 & MMC_CAP2_HS200)) {
>> >> >  +                              mmc_card_set_hs200(card);
>> >> >  +                      mmc_set_timing(card->host,
>> >> MMC_TIMING_MMC_HS200)
>> >> >  +                      } else {
>> >> >  +                              mmc_card_set_highspeed(card);
>> >> >  +                              mmc_set_timing(card->host,
>> >> > MMC_TIMING_MMC_HS)
>> >> >  +                      }
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >>               }
>> >> >>       }
>> >> >> @@ -933,7 +964,7 @@ static int mmc_init_card(struct mmc_host
>> *host,
>> >> u32
>> >> >> ocr,
>> >> >>        */
>> >> >>       max_dtr = (unsigned int)-1;
>> >> >>
>> >> >> -     if (mmc_card_highspeed(card)) {
>> >> >> +     if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
>> >> >>               if (max_dtr > card->ext_csd.hs_max_dtr)
>> >> >>                       max_dtr = card->ext_csd.hs_max_dtr;
>> >> >>       } else if (max_dtr > card->csd.max_dtr) {
>> >> >> @@ -959,6 +990,18 @@ static int mmc_init_card(struct mmc_host
>> *host,
>> >> >> u32 ocr,
>> >> >>       }
>> >> >>
>> >> >>       /*
>> >> >> +      * Indicate HS200 SDR mode (if supported).
>> >> >> +      */
>> >> >> +     if (mmc_card_hs200(card)) {
>> >> >> +             if ((card->ext_csd.card_type &
>> >> EXT_CSD_CARD_TYPE_SDR_1_8V)
>> >> >> +                     && (host->caps2 & MMC_CAP2_HS200_1_8V_SDR))
>> >> >> +                             hs_sdr = MMC_1_8V_SDR_MODE;
>> >> >> +             else if ((card->ext_csd.card_type &
>> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
>> >> >> +                     && (host->caps2 & MMC_CAP2_HS200_1_2V_SDR))
>> >> >> +                             hs_sdr = MMC_1_2V_SDR_MODE;
>> >> >> +     }
>> >> >> +
>> >> >> +     /*
>> >> >>        * Activate wide bus and DDR (if supported).
>> >> >>        */
>> >> >>       if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
>> >> >> @@ -998,6 +1041,17 @@ static int mmc_init_card(struct mmc_host
>> >> *host,
>> >> >> u32 ocr,
>> >> >>                       if (!err) {
>> >> >>                               mmc_set_bus_width(card->host,
>> >> bus_width);
>> >> >>
>> >> >> +                             if ((host->caps2 & MMC_CAP2_HS200)
>> &&
>> >> >> +                                 card->host->ops-
>> >execute_tuning)
>> >> >> +                                     err = card->host->ops-> \
>> >> >> +                                           execute_tuning(card-
>> >> >host,
>> >> >> +
>> >> > MMC_SEND_TUNING_BLOCK_HS200);
>> >> >
>> >> >
>> >> > execute_tuning should be done right after the timing is changed to
>> >> HS200 and
>> >> > clock rate is changed to 200Mhz. This is not the correct sequence
>> to
>> >> call
>> >> > the execute_tuning().
>> >> > As told earlier, It is mentioned in the spec that tuning should be
>> >> executed after change of buswidth (mandatory). Also it mentions that
>> >> "The host may invoke the HS200 tuning sequence, by sending CMD21 to
>> the
>> >> device". It means that
>> >>  after setting the HS200 mode, Changing to freq > 52Mhz and changing
>> >> the bus width tuning can be executed anytime to identify the
>> sampling
>> >> point to read.(By anytime i mean before actual block read
>> Operation).
>> >> Can you please point me to the place in the spec where it specifies
>> >> tuning should be done immediately after freq change (may be i missed
>> >> to read it).
>> >
>> >
>> > Ok. let me ask you this. Why do we run the execute_tuning()? It's to
>> tune
>> > the sampling clock generator of host controller before you start any
>> read
>> > operation (on command line or data line) from card. If you don't tune
>> the
>> > sampling clock generator before the read operation (after changing
>> the
>> > timing to HS200 and clock rate to 200mhz), you can't be sure that
>> read
>> > operation from card will be completed without errors. You may get the
>> data /
>> > cmd response CRC errors. At least this will surely fail on our MSM
>> SDCC host
>> > controller. That's what we had faced with SD3.0 UHS-I tuning as well
>> as
>> > mentioned in http://www.spinics.net/lists/linux-arm-
>> msm/msg03867.html.
>
>> > this tuning is done before any read opration for the best bus width
>> supported.
> Agreed. But can we be sure that "command response" for bus width change via
> CMD6, will not have any command CRC failures if tuning is not done?
All responses are sent on CMD line not on data lines, And sampling is
done for Data lines before reading. So command CRC failure doesnt
depend on tuning. If you get error during CMD6 it could be that device
cannot support the bus width at the set frequency.
>
>> ps:Chris need your comment on this
>> >
>> >> >> +
>> >> >> +                             if (err) {
>> >> >> +                                     pr_warning("tuning
>> execution
>> >> > failed\n");
>> >> >> +                                     continue;
>> >> >> +                             }
>> >> >> +
>> >> >>                               /*
>> >> >>                                * If controller can't handle bus
>> >> width
>> >> > test,
>> >> >>                                * compare ext_csd previously read
>> in
>> >> 1 bit
>> >> >> mode
>> >> >> @@ -1056,6 +1110,15 @@ static int mmc_init_card(struct mmc_host
>> >> *host,
>> >> >> u32 ocr,
>> >> >>                       mmc_card_set_ddr_mode(card);
>> >> >>                       mmc_set_timing(card->host,
>> >> MMC_TIMING_UHS_DDR50);
>> >> >>                       mmc_set_bus_width(card->host, bus_width);
>> >> >> +             } else if (hs_sdr) {
>> >> >> +                     if (hs_sdr == EXT_CSD_CARD_TYPE_SDR_1_2V) {
>> >> >> +                             err = mmc_set_signal_voltage(host,
>> >> >> +                                     MMC_SIGNAL_VOLTAGE_120, 0);
>> >> >> +                             if (err)
>> >> >> +                                     goto err;
>> >> >> +                     }
>> >> >> +                     mmc_set_timing(card->host,
>> MMC_TIMING_MMC_HS);
>> >> >> +                     mmc_set_bus_width(card->host, bus_width);
>> >> >>               }
>> >> >>       }
>> >> >>
>> >> >> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
>> >> >> index 1d5a3bd..c1d3ee3 100644
>> >> >> --- a/drivers/mmc/core/sd.c
>> >> >> +++ b/drivers/mmc/core/sd.c
>> >> >> @@ -660,7 +660,8 @@ static int mmc_sd_init_uhs_card(struct
>> mmc_card
>> >> >> *card)
>> >> >>
>> >> >>       /* SPI mode doesn't define CMD19 */
>> >> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
>> >> >> >execute_tuning)
>> >> >> -             err = card->host->ops->execute_tuning(card->host);
>> >> >> +             err = card->host->ops->execute_tuning(card->host,
>> >>   \
>> >> >> +
>> >> > MMC_SEND_TUNING_BLOCK);
>> >> >>
>> >> >>  out:
>> >> >>       kfree(status);
>> >> >> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
>> >> >> index 8c04f7f..8ef8817 100644
>> >> >> --- a/drivers/mmc/core/sdio.c
>> >> >> +++ b/drivers/mmc/core/sdio.c
>> >> >> @@ -14,6 +14,7 @@
>> >> >>
>> >> >>  #include <linux/mmc/host.h>
>> >> >>  #include <linux/mmc/card.h>
>> >> >> +#include <linux/mmc/mmc.h>
>> >> >>  #include <linux/mmc/sdio.h>
>> >> >>  #include <linux/mmc/sdio_func.h>
>> >> >>  #include <linux/mmc/sdio_ids.h>
>> >> >> @@ -556,7 +557,8 @@ static int mmc_sdio_init_uhs_card(struct
>> >> mmc_card
>> >> >> *card)
>> >> >>
>> >> >>       /* Initialize and start re-tuning timer */
>> >> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
>> >> >> >execute_tuning)
>> >> >> -             err = card->host->ops->execute_tuning(card->host);
>> >> >> +             err = card->host->ops->execute_tuning(card->host,
>> >> >> +
>> >> > MMC_SEND_TUNING_BLOCK);
>> >> >>
>> >> >>  out:
>> >> >>
>> >> >> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>> >> >> index a7c2311..13d74bb 100644
>> >> >> --- a/drivers/mmc/host/sdhci.c
>> >> >> +++ b/drivers/mmc/host/sdhci.c
>> >> >> @@ -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
>> >> >> @@ -1016,7 +1016,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
>> */
>> >> >> @@ -1673,7 +1674,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;
>> >> >> @@ -1694,10 +1695,13 @@ static int sdhci_execute_tuning(struct
>> >> mmc_host
>> >> >> *mmc)
>> >> >>        * Host Controller needs tuning only in case of SDR104 mode
>> >> >>        * and for SDR50 mode when Use Tuning for SDR50 is set in
>> >> >>        * Capabilities register.
>> >> >> +      * If the Host Controller supports the HS200 mode then
>> tuning
>> >> >> +      * function has to be executed.
>> >> >>        */
>> >> >>       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)))
>> >> >> +         (host->flags & SDHCI_SDR50_NEEDS_TUNING)) ||
>> >> >> +         (host->flags & SDHCI_HS200_NEEDS_TUNING))
>> >> >>               ctrl |= SDHCI_CTRL_EXEC_TUNING;
>> >> >>       else {
>> >> >>               spin_unlock(&host->lock);
>> >> >> @@ -1733,7 +1737,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;
>> >> >> @@ -1748,7 +1752,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.
>> >> >> @@ -2131,12 +2145,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;
>> >> >> @@ -2741,6 +2757,10 @@ int sdhci_add_host(struct sdhci_host
>> *host)
>> >> >>       if (caps[1] & SDHCI_USE_SDR50_TUNING)
>> >> >>               host->flags |= SDHCI_SDR50_NEEDS_TUNING;
>> >> >>
>> >> >> +     /* Does the host needs 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;
>> >> >> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> >> >> index 534974c..e76f649 100644
>> >> >> --- a/include/linux/mmc/card.h
>> >> >> +++ b/include/linux/mmc/card.h
>> >> >> @@ -209,6 +209,7 @@ struct mmc_card {
>> >> >>  #define MMC_STATE_HIGHSPEED_DDR (1<<4)               /* card is
>> in
>> >> high
>> >> >> speed mode */
>> >> >>  #define MMC_STATE_ULTRAHIGHSPEED (1<<5)              /* card is
>> in
>> >> ultra
>> >> >> high speed mode */
>> >> >>  #define MMC_CARD_SDXC                (1<<6)          /* card is
>> >> SDXC */
>> >> >> +#define MMC_STATE_HIGHSPEED_200      (1<<7)  /* card is in HS200
>> >> >> mode */
>> >> >>       unsigned int            quirks;         /* card quirks */
>> >> >>  #define MMC_QUIRK_LENIENT_FN0        (1<<0)          /* allow
>> SDIO
>> >> FN0
>> >> >> writes outside of the VS CCCR range */
>> >> >>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func-
>> >> >> >cur_blksize */
>> >> >> @@ -365,6 +366,7 @@ static inline void __maybe_unused
>> >> >> remove_quirk(struct mmc_card *card, int data)
>> >> >>  #define mmc_card_present(c)  ((c)->state & MMC_STATE_PRESENT)
>> >> >>  #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
>> >> >>  #define mmc_card_highspeed(c)        ((c)->state &
>> >> MMC_STATE_HIGHSPEED)
>> >> >> +#define mmc_card_hs200(c)    ((c)->state &
>> MMC_STATE_HIGHSPEED_200)
>> >> >>  #define mmc_card_blockaddr(c)        ((c)->state &
>> >> MMC_STATE_BLOCKADDR)
>> >> >>  #define mmc_card_ddr_mode(c) ((c)->state &
>> MMC_STATE_HIGHSPEED_DDR)
>> >> >>  #define mmc_card_uhs(c)              ((c)->state &
>> >> >> MMC_STATE_ULTRAHIGHSPEED)
>> >> >> @@ -374,6 +376,7 @@ static inline void __maybe_unused
>> >> >> remove_quirk(struct mmc_card *card, int data)
>> >> >>  #define mmc_card_set_present(c)      ((c)->state |=
>> >> MMC_STATE_PRESENT)
>> >> >>  #define mmc_card_set_readonly(c) ((c)->state |=
>> MMC_STATE_READONLY)
>> >> >>  #define mmc_card_set_highspeed(c) ((c)->state |=
>> >> MMC_STATE_HIGHSPEED)
>> >> >> +#define mmc_card_set_hs200(c)        ((c)->state |=
>> >> >> MMC_STATE_HIGHSPEED_200)
>> >> >>  #define mmc_card_set_blockaddr(c) ((c)->state |=
>> >> MMC_STATE_BLOCKADDR)
>> >> >>  #define mmc_card_set_ddr_mode(c) ((c)->state |=
>> >> >> MMC_STATE_HIGHSPEED_DDR)
>> >> >>  #define mmc_card_set_uhs(c) ((c)->state |=
>> >> MMC_STATE_ULTRAHIGHSPEED)
>> >> >> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> >> >> index 706f722..5eac57a 100644
>> >> >> --- a/include/linux/mmc/host.h
>> >> >> +++ b/include/linux/mmc/host.h
>> >> >> @@ -50,6 +50,7 @@ struct mmc_ios {
>> >> >>
>> >> >>  #define MMC_TIMING_LEGACY    0
>> >> >>  #define MMC_TIMING_MMC_HS    1
>> >> >> +#define MMC_TIMING_MMC_HS200 2
>> >> >>  #define MMC_TIMING_SD_HS     2
>> >> >>  #define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY
>> >> >>  #define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS
>> >> >> @@ -60,6 +61,8 @@ struct mmc_ios {
>> >> >>  #define MMC_SDR_MODE         0
>> >> >>  #define MMC_1_2V_DDR_MODE    1
>> >> >>  #define MMC_1_8V_DDR_MODE    2
>> >> >> +#define MMC_1_2V_SDR_MODE    3
>> >> >> +#define MMC_1_8V_SDR_MODE    4
>> >> >>
>> >> >>       unsigned char   signal_voltage;         /* signalling
>> voltage
>> >> >> (1.8V or 3.3V) */
>> >> >>
>> >> >> @@ -148,7 +151,9 @@ struct mmc_host_ops {
>> >> >>       void    (*init_card)(struct mmc_host *host, struct mmc_card
>> >> *card);
>> >> >>
>> >> >>       int     (*start_signal_voltage_switch)(struct mmc_host
>> *host,
>> >> >> struct mmc_ios *ios);
>> >> >> -     int     (*execute_tuning)(struct mmc_host *host);
>> >> >> +
>> >> >> +     /* The tuning command opcode value is different for SD and
>> >> eMMC
>> >> >> cards */
>> >> >> +     int     (*execute_tuning)(struct mmc_host *host, u32
>> opcode);
>> >> >>       void    (*enable_preset_value)(struct mmc_host *host, bool
>> >> enable);
>> >> >>       int     (*select_drive_strength)(unsigned int max_dtr, int
>> >> >> host_drv, int card_drv);
>> >> >>       void    (*hw_reset)(struct mmc_host *host);
>> >> >> @@ -242,6 +247,10 @@ struct mmc_host {
>> >> >>  #define MMC_CAP2_CACHE_CTRL  (1 << 1)        /* Allow cache
>> control
>> >> */
>> >> >>  #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)    /* Notify poweroff
>> >> >> supported */
>> >> >>  #define MMC_CAP2_NO_MULTI_READ       (1 << 3)        /*
>> Multiblock
>> >> reads
>> >> >> don't work */
>> >> >> +#define MMC_CAP2_HS200_1_8V_SDR      (1 << 4)        /* can
>> support
>> >> */
>> >> >> +#define MMC_CAP2_HS200_1_2V_SDR      (1 << 5)        /* can
>> support
>> >> */
>> >> >> +#define MMC_CAP2_HS200               (MMC_CAP2_HS200_1_8V_SDR |
>> \
>> >> >> +                              MMC_CAP2_HS200_1_2V_SDR)
>> >> >>
>> >> >>       mmc_pm_flag_t           pm_caps;        /* supported pm
>> >> features */
>> >> >>       unsigned int        power_notify_type;
>> >> >> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> >> >> index 0e71356..7996272 100644
>> >> >> --- a/include/linux/mmc/mmc.h
>> >> >> +++ b/include/linux/mmc/mmc.h
>> >> >> @@ -51,6 +51,7 @@
>> >> >>  #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr
>> R1
>> >> >> */
>> >> >>  #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr
>> R1
>> >> >> */
>> >> >>  #define MMC_SEND_TUNING_BLOCK    19   /* adtc
>>  R1
>> >> >> */
>> >> >> +#define MMC_SEND_TUNING_BLOCK_HS200  21      /* adtc R1  */
>> >> >>
>> >> >>    /* class 3 */
>> >> >>  #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr
>> R1
>> >> >> */
>> >> >> @@ -333,13 +334,76 @@ struct _mmc_csd {
>> >> >>
>> >> >>  #define EXT_CSD_CARD_TYPE_26 (1<<0)  /* Card can run at 26MHz */
>> >> >>  #define EXT_CSD_CARD_TYPE_52 (1<<1)  /* Card can run at 52MHz */
>> >> >> -#define EXT_CSD_CARD_TYPE_MASK       0xF     /* Mask out
>> reserved
>> >> bits */
>> >> >> +#define EXT_CSD_CARD_TYPE_MASK       0x3F    /* Mask out
>> reserved
>> >> bits */
>> >> >>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at
>> >> 52MHz
>> >> >> */
>> >> >>                                            /* DDR mode @1.8V or
>> 3V
>> >> I/O */
>> >> >>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at
>> >> 52MHz
>> >> >> */
>> >> >>                                            /* DDR mode @1.2V I/O
>> */
>> >> >>  #define EXT_CSD_CARD_TYPE_DDR_52
>> (EXT_CSD_CARD_TYPE_DDR_1_8V
>> >>  \
>> >> >>                                       |
>> EXT_CSD_CARD_TYPE_DDR_1_2V)
>> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V   (1<<4)  /* Card can run at
>> >> >> 200MHz */
>> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V   (1<<5)  /* Card can run at
>> >> >> 200MHz */
>> >> >> +                                             /* SDR mode @1.2V
>> I/O
>> >> */
>> >> >> +
>> >> >> +#define EXT_CSD_CARD_TYPE_SDR_200    (EXT_CSD_CARD_TYPE_SDR_1_8V
>> >>   \
>> >> >> +                                     |
>> EXT_CSD_CARD_TYPE_SDR_1_2V)
>> >> >> +
>> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL    (EXT_CSD_CARD_TYPE_SDR_200
>> >>  \
>> >> >> +                                     | EXT_CSD_CARD_TYPE_52
>> >>  \
>> >> >> +                                     | EXT_CSD_CARD_TYPE_26)
>> >> >> +
>> >> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_2V_ALL
>> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V     \
>> >> >> +                                     | EXT_CSD_CARD_TYPE_52
>> >>  \
>> >> >> +                                     | EXT_CSD_CARD_TYPE_26)
>> >> >> +
>> >> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_8V_ALL
>> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V     \
>> >> >> +                                     | EXT_CSD_CARD_TYPE_52
>> >>  \
>> >> >> +                                     | EXT_CSD_CARD_TYPE_26)
>> >> >> +
>> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V
>> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_DDR_1_8V
>> >> > \
>> >> >> +                                             |
>> EXT_CSD_CARD_TYPE_52
>> >> > \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_26)
>> >> >> +
>> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V
>> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_DDR_1_8V
>> >> > \
>> >> >> +                                             |
>> EXT_CSD_CARD_TYPE_52
>> >> > \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_26)
>> >> >> +
>> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V
>> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_DDR_1_2V
>> >> > \
>> >> >> +                                             |
>> EXT_CSD_CARD_TYPE_52
>> >> > \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_26)
>> >> >> +
>> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V
>> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_DDR_1_2V
>> >> > \
>> >> >> +                                             |
>> EXT_CSD_CARD_TYPE_52
>> >> > \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_26)
>> >> >> +
>> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52
>> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_DDR_52
>> >> > \
>> >> >> +                                             |
>> EXT_CSD_CARD_TYPE_52
>> >> > \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_26)
>> >> >> +
>> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52
>> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_DDR_52
>> >> > \
>> >> >> +                                             |
>> EXT_CSD_CARD_TYPE_52
>> >> > \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_26)
>> >> >> +
>> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V
>> >> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_DDR_1_8V
>> >> > \
>> >> >> +                                             |
>> EXT_CSD_CARD_TYPE_52
>> >> > \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_26)
>> >> >> +
>> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V
>> >> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_DDR_1_2V
>> >> > \
>> >> >> +                                             |
>> EXT_CSD_CARD_TYPE_52
>> >> > \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_26)
>> >> >> +
>> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52
>> >> (EXT_CSD_CARD_TYPE_SDR_200
>> >> >> \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_DDR_52
>> >> > \
>> >> >> +                                             |
>> EXT_CSD_CARD_TYPE_52
>> >> > \
>> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_26)
>> >> >>
>> >> >>  #define EXT_CSD_BUS_WIDTH_1  0       /* Card is in 1 bit mode */
>> >> >>  #define EXT_CSD_BUS_WIDTH_4  1       /* Card is in 4 bit mode */
>> >> >> diff --git a/include/linux/mmc/sdhci.h
>> b/include/linux/mmc/sdhci.h
>> >> >> index e4b6935..d9a2222 100644
>> >> >> --- a/include/linux/mmc/sdhci.h
>> >> >> +++ b/include/linux/mmc/sdhci.h
>> >> >> @@ -121,6 +121,7 @@ struct sdhci_host {
>> >> >>  #define SDHCI_AUTO_CMD23     (1<<7)  /* Auto CMD23 support */
>> >> >>  #define SDHCI_PV_ENABLED     (1<<8)  /* Preset value enabled */
>> >> >>  #define SDHCI_SDIO_IRQ_ENABLED       (1<<9)  /* SDIO irq enabled
>> */
>> >> >> +#define SDHCI_HS200_NEEDS_TUNING (1<<10)     /* HS200 needs
>> tuning
>> >> */
>> >> >>
>> >> >>       unsigned int version;   /* SDHCI spec. version */
>> >> >>
>> >> >> --
>> >> >> 1.7.1
>> >> >>
>> >> >> --
>> >> >> To unsubscribe from this list: send the line "unsubscribe linux-
>> mmc"
>> >> in
>> >> >> the body of a message to majordomo@vger.kernel.org
>> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
>> info.html
>> >> >
>> >> > --
>> >> > To unsubscribe from this list: send the line "unsubscribe linux-
>> mmc"
>> >> in
>> >> > the body of a message to majordomo@vger.kernel.org
>> >> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> >> >
>> >> --
>> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc"
>> in
>> >> the body of a message to majordomo@vger.kernel.org
>> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> >
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
Subhash Jadavani Dec. 5, 2011, 6:16 a.m. UTC | #7
> -----Original Message-----
> From: Girish K S [mailto:girish.shivananjappa@linaro.org]
> Sent: Friday, December 02, 2011 5:08 PM
> To: Subhash Jadavani
> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
> soc@vger.kernel.org; Chris Ball
> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
> 
> On 2 December 2011 00:02, Subhash Jadavani <subhashj@codeaurora.org>
> wrote:
> >
> >
> >> -----Original Message-----
> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
> >> owner@vger.kernel.org] On Behalf Of Girish K S
> >> Sent: Thursday, December 01, 2011 7:48 PM
> >> To: Subhash Jadavani
> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
> >> soc@vger.kernel.org; Chris Ball
> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
> >>
> >> On 1 December 2011 16:27, Subhash Jadavani <subhashj@codeaurora.org>
> >> wrote:
> >> >
> >> >
> >> >> -----Original Message-----
> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
> >> >> Sent: Thursday, December 01, 2011 3:58 PM
> >> >> To: Subhash Jadavani
> >> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
> >> >> soc@vger.kernel.org; Chris Ball
> >> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC
> 4.5
> >> >>
> >> >> On 1 December 2011 15:33, Subhash Jadavani
> <subhashj@codeaurora.org>
> >> >> wrote:
> >> >> > Hi Girish,
> >> >> >
> >> >> >> -----Original Message-----
> >> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
> >> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
> >> >> >> Sent: Wednesday, November 30, 2011 2:24 PM
> >> >> >> To: linux-mmc@vger.kernel.org
> >> >> >> Cc: patches@linaro.org; linux-samsung-soc@vger.kernel.org;
> >> >> >> subhashj@codeaurora.org; Girish K S; Chris Ball
> >> >> >> Subject: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
> >> >> >>
> >> >> >> This patch adds the support of the HS200 bus speed for eMMC
> 4.5
> >> >> >> devices.
> >> >> >> The eMMC 4.5 devices have support for 200MHz bus speed.The mmc
> >> core
> >> >> and
> >> >> >> host modules have been touched to add support for this module.
> >> >> >>
> >> >> >> It is necessary to know the card type in the sdhci.c file to
> add
> >> >> >> support
> >> >> >> for eMMC tuning function. So card.h file is included to import
> >> the
> >> >> card
> >> >> >> data structure.
> >> >> >>
> >> >> >> cc: Chris Ball <cjb@laptop.org>
> >> >> >> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
> >> >> >> ---
> >> >> >> Changes in v5:
> >> >> >>       Reduced the case statements for better code readability.
> >> >> Removed
> >> >> >>       unused macro definitions. Modified the tuning function
> >> >> prototype
> >> >> >>       and definition to support tuning for both SD and eMMC
> >> cards.
> >> >> >> Changes in v4:
> >> >> >>       Rebased onto chris-mmc/mmc-next branch. This patch is
> >> >> >> successfully
> >> >> >>       applied on commit with id
> >> >> >> de022ed3fdc14808299b2fa66dbb1ed5ab921912.
> >> >> >> Changes in v3:
> >> >> >>       In the previous commits of chris-mmc/mmc-next branch,
> the
> >> >> patch
> >> >> >> with
> >> >> >>       commit id (c0f22a2c92e357e7cb3988b0b13034d70b7461f9)
> >> defines
> >> >> >> caps2 for
> >> >> >>       more capabilities. This patch version deletes the member
> >> >> >> ext_caps(created
> >> >> >>       in my earlier patch) from struct mmc_host and reuses
> >> already
> >> >> >> accepted
> >> >> >>       caps2 member.
> >> >> >> Changes in v2:
> >> >> >>       Rebased to latest chris-mmc/mmc-next branch. Resolved
> >> >> indentation
> >> >> >>       problems identified in review. This patch has to be
> applied
> >> >> >> before
> >> >> >>       the patch released for modifying the printk messages.
> >> >> >> Changes in v1:
> >> >> >>       Case statements in switch that produce same result have
> >> >> >>       been combined to reduce repeated assignments.
> >> >> >>       patch recreated after rebase to chris balls mmc-next
> >> branch.
> >> >> >>
> >> >> >>  drivers/mmc/core/bus.c    |    3 +-
> >> >> >>  drivers/mmc/core/mmc.c    |   77
> >> >> >> ++++++++++++++++++++++++++++++++++++++++----
> >> >> >>  drivers/mmc/core/sd.c     |    3 +-
> >> >> >>  drivers/mmc/core/sdio.c   |    4 ++-
> >> >> >>  drivers/mmc/host/sdhci.c  |   38 +++++++++++++++++-----
> >> >> >>  include/linux/mmc/card.h  |    3 ++
> >> >> >>  include/linux/mmc/host.h  |   11 ++++++-
> >> >> >>  include/linux/mmc/mmc.h   |   66
> >> >> >> ++++++++++++++++++++++++++++++++++++++-
> >> >> >>  include/linux/mmc/sdhci.h |    1 +
> >> >> >>  9 files changed, 185 insertions(+), 21 deletions(-)
> >> >> >>
> >> >> >> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> >> >> >> index 5639fdf..83c9f8d 100644
> >> >> >> --- a/drivers/mmc/core/bus.c
> >> >> >> +++ b/drivers/mmc/core/bus.c
> >> >> >> @@ -301,10 +301,11 @@ int mmc_add_card(struct mmc_card *card)
> >> >> >>                       mmc_card_ddr_mode(card) ? "DDR " : "",
> >> >> >>                       type);
> >> >> >>       } else {
> >> >> >> -             printk(KERN_INFO "%s: new %s%s%s card at address
> >> >> %04x\n",
> >> >> >> +             pr_info("%s: new %s%s%s%s card at address
> %04x\n",
> >> >> >>                       mmc_hostname(card->host),
> >> >> >>                       mmc_card_uhs(card) ? "ultra high speed "
> :
> >> >> >>                       (mmc_card_highspeed(card) ? "high speed
> " :
> >> >> ""),
> >> >> >> +                     (mmc_card_hs200(card) ? "HS200 " : ""),
> >> >> >>                       mmc_card_ddr_mode(card) ? "DDR " : "",
> >> >> >>                       type, card->rca);
> >> >> >>       }
> >> >> >> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> >> >> >> index a1223bd..f4124d6 100644
> >> >> >> --- a/drivers/mmc/core/mmc.c
> >> >> >> +++ b/drivers/mmc/core/mmc.c
> >> >> >> @@ -285,6 +285,27 @@ static int mmc_read_ext_csd(struct
> mmc_card
> >> >> *card,
> >> >> >> u8 *ext_csd)
> >> >> >>       }
> >> >> >>       card->ext_csd.raw_card_type =
> ext_csd[EXT_CSD_CARD_TYPE];
> >> >> >>       switch (ext_csd[EXT_CSD_CARD_TYPE] &
> >> EXT_CSD_CARD_TYPE_MASK) {
> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL:
> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
> >> >> >> +             card->ext_csd.card_type =
> >> EXT_CSD_CARD_TYPE_SDR_200;
> >> >> >> +             break;
> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
> >> >> >> +             card->ext_csd.card_type =
> >> EXT_CSD_CARD_TYPE_SDR_1_2V;
> >> >> >> +             break;
> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
> >> >> >> +             card->ext_csd.card_type =
> >> EXT_CSD_CARD_TYPE_SDR_1_8V;
> >> >> >> +             break;
> >> >> >>       case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
> >> >> >>            EXT_CSD_CARD_TYPE_26:
> >> >> >>               card->ext_csd.hs_max_dtr = 52000000;
> >> >> >> @@ -699,6 +720,7 @@ static int mmc_init_card(struct mmc_host
> >> *host,
> >> >> u32
> >> >> >> ocr,
> >> >> >>  {
> >> >> >>       struct mmc_card *card;
> >> >> >>       int err, ddr = 0;
> >> >> >> +     int hs_sdr = 0;
> >> >> >>       u32 cid[4];
> >> >> >>       unsigned int max_dtr;
> >> >> >>       u32 rocr;
> >> >> >> @@ -894,11 +916,16 @@ static int mmc_init_card(struct mmc_host
> >> >> *host,
> >> >> >> u32 ocr,
> >> >> >>       /*
> >> >> >>        * Activate high speed (if supported)
> >> >> >>        */
> >> >> >> -     if ((card->ext_csd.hs_max_dtr != 0) &&
> >> >> >> -             (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
> >> >> >> -             err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >> >> -                              EXT_CSD_HS_TIMING, 1,
> >> >> >> -                              card-
> >ext_csd.generic_cmd6_time);
> >> >> >> +     if (card->ext_csd.hs_max_dtr != 0) {
> >> >> >> +             err = 0;
> >> >> >> +             if ((card->ext_csd.hs_max_dtr > 52000000) &&
> >> >> >> +                 (host->caps2 & MMC_CAP2_HS200))
> >> >> >> +                     err = mmc_switch(card,
> >> EXT_CSD_CMD_SET_NORMAL,
> >> >> >> +                                      EXT_CSD_HS_TIMING, 2,
> 0);
> >> >> >> +             else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
> >> >> >> +                     err = mmc_switch(card,
> >> EXT_CSD_CMD_SET_NORMAL,
> >> >> >> +                                      EXT_CSD_HS_TIMING, 1,
> 0);
> >> >> >> +
> >> >> >>               if (err && err != -EBADMSG)
> >> >> >>                       goto free_card;
> >> >> >>
> >> >> >> @@ -907,7 +934,11 @@ static int mmc_init_card(struct mmc_host
> >> *host,
> >> >> >> u32 ocr,
> >> >> >>                              mmc_hostname(card->host));
> >> >> >>                       err = 0;
> >> >> >>               } else {
> >> >> >> -                     mmc_card_set_highspeed(card);
> >> >> >> +                     if ((card->ext_csd.hs_max_dtr >
> 52000000)
> >> &&
> >> >> >> +                         (host->caps2 & MMC_CAP2_HS200))
> >> >> >> +                             mmc_card_set_hs200(card);
> >> >> >> +                     else
> >> >> >> +                             mmc_card_set_highspeed(card);
> >> >> >>                       mmc_set_timing(card->host,
> >> MMC_TIMING_MMC_HS);
> >> >> >
> >> >> > MMC_TIMING_MMC_HS200 is defined but still not used.
> >> >> >
> >> >> > So I guess it should be like this ::
> >> >> >  +                      if ((card->ext_csd.hs_max_dtr >
> 52000000)
> >> &&
> >> >> >  +                          (host->caps2 & MMC_CAP2_HS200)) {
> >> >> >  +                              mmc_card_set_hs200(card);
> >> >> >  +                      mmc_set_timing(card->host,
> >> >> MMC_TIMING_MMC_HS200)
> >> >> >  +                      } else {
> >> >> >  +                              mmc_card_set_highspeed(card);
> >> >> >  +                              mmc_set_timing(card->host,
> >> >> > MMC_TIMING_MMC_HS)
> >> >> >  +                      }
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >> >>               }
> >> >> >>       }
> >> >> >> @@ -933,7 +964,7 @@ static int mmc_init_card(struct mmc_host
> >> *host,
> >> >> u32
> >> >> >> ocr,
> >> >> >>        */
> >> >> >>       max_dtr = (unsigned int)-1;
> >> >> >>
> >> >> >> -     if (mmc_card_highspeed(card)) {
> >> >> >> +     if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
> >> >> >>               if (max_dtr > card->ext_csd.hs_max_dtr)
> >> >> >>                       max_dtr = card->ext_csd.hs_max_dtr;
> >> >> >>       } else if (max_dtr > card->csd.max_dtr) {
> >> >> >> @@ -959,6 +990,18 @@ static int mmc_init_card(struct mmc_host
> >> *host,
> >> >> >> u32 ocr,
> >> >> >>       }
> >> >> >>
> >> >> >>       /*
> >> >> >> +      * Indicate HS200 SDR mode (if supported).
> >> >> >> +      */
> >> >> >> +     if (mmc_card_hs200(card)) {
> >> >> >> +             if ((card->ext_csd.card_type &
> >> >> EXT_CSD_CARD_TYPE_SDR_1_8V)
> >> >> >> +                     && (host->caps2 &
> MMC_CAP2_HS200_1_8V_SDR))
> >> >> >> +                             hs_sdr = MMC_1_8V_SDR_MODE;
> >> >> >> +             else if ((card->ext_csd.card_type &
> >> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
> >> >> >> +                     && (host->caps2 &
> MMC_CAP2_HS200_1_2V_SDR))
> >> >> >> +                             hs_sdr = MMC_1_2V_SDR_MODE;
> >> >> >> +     }
> >> >> >> +
> >> >> >> +     /*
> >> >> >>        * Activate wide bus and DDR (if supported).
> >> >> >>        */
> >> >> >>       if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
> >> >> >> @@ -998,6 +1041,17 @@ static int mmc_init_card(struct mmc_host
> >> >> *host,
> >> >> >> u32 ocr,
> >> >> >>                       if (!err) {
> >> >> >>                               mmc_set_bus_width(card->host,
> >> >> bus_width);
> >> >> >>
> >> >> >> +                             if ((host->caps2 &
> MMC_CAP2_HS200)
> >> &&
> >> >> >> +                                 card->host->ops-
> >> >execute_tuning)
> >> >> >> +                                     err = card->host->ops->
> \
> >> >> >> +
> execute_tuning(card-
> >> >> >host,
> >> >> >> +
> >> >> > MMC_SEND_TUNING_BLOCK_HS200);
> >> >> >
> >> >> >
> >> >> > execute_tuning should be done right after the timing is changed
> to
> >> >> HS200 and
> >> >> > clock rate is changed to 200Mhz. This is not the correct
> sequence
> >> to
> >> >> call
> >> >> > the execute_tuning().
> >> >> > As told earlier, It is mentioned in the spec that tuning should
> be
> >> >> executed after change of buswidth (mandatory). Also it mentions
> that
> >> >> "The host may invoke the HS200 tuning sequence, by sending CMD21
> to
> >> the
> >> >> device". It means that
> >> >>  after setting the HS200 mode, Changing to freq > 52Mhz and
> changing
> >> >> the bus width tuning can be executed anytime to identify the
> >> sampling
> >> >> point to read.(By anytime i mean before actual block read
> >> Operation).
> >> >> Can you please point me to the place in the spec where it
> specifies
> >> >> tuning should be done immediately after freq change (may be i
> missed
> >> >> to read it).
> >> >
> >> >
> >> > Ok. let me ask you this. Why do we run the execute_tuning()? It's
> to
> >> tune
> >> > the sampling clock generator of host controller before you start
> any
> >> read
> >> > operation (on command line or data line) from card. If you don't
> tune
> >> the
> >> > sampling clock generator before the read operation (after changing
> >> the
> >> > timing to HS200 and clock rate to 200mhz), you can't be sure that
> >> read
> >> > operation from card will be completed without errors. You may get
> the
> >> data /
> >> > cmd response CRC errors. At least this will surely fail on our MSM
> >> SDCC host
> >> > controller. That's what we had faced with SD3.0 UHS-I tuning as
> well
> >> as
> >> > mentioned in http://www.spinics.net/lists/linux-arm-
> >> msm/msg03867.html.
> >
> >> > this tuning is done before any read opration for the best bus
> width
> >> supported.
> > Agreed. But can we be sure that "command response" for bus width
> change via
> > CMD6, will not have any command CRC failures if tuning is not done?
> All responses are sent on CMD line not on data lines, And sampling is
> done for Data lines before reading. So command CRC failure doesnt
> depend on tuning. If you get error during CMD6 it could be that device
> cannot support the bus width at the set frequency.

I guess it's not the correct assumption here. Sampling point tuning is to
tune the sampling point for data received on both CMD and DATA lines (not
just data lines). I can't find detailed mentioning of this in eMMC4.5
(that's the documentation short coming, you can even confirm whether tuning
procedure is required for CMD line or not from JEDEC) but SD3.01
specification does mention this tuning procedure in great details. NOTE:
eMMC4.5 HS200 mode is mostly inspired from SD3.01 UHS-I bus speed modes.

Section " 4.2.4.5 Tuning Command" in "SD3.01 - Simplified
(Part_1_Physical_Layer_Simplified_Specification_Ver_3.01_Final_100518)"
specification(can be downloaded from here:
https://www.sdcard.org/downloads/pls/), clearly states this:

4.2.4.5 Tuning Command
CMD19 is defined for Send Tuning Block Command. R1 type response is defined.
CMD19 can be
executed in transfer state of 1.8V signaling mode while the card is
unlocked. The other case, CMD19 is
treated as illegal command. Data block, carried by DAT[3:0], contains a
pattern for tuning sampling
position to receive data on the CMD and DAT[3:0] line. The block length of
CMD19 is fixed and CMD16
is not required.

So before tuning, you may get the Command CRC errors in HS200 mode.

Regards,
Subhash

> >
> >> ps:Chris need your comment on this
> >> >
> >> >> >> +
> >> >> >> +                             if (err) {
> >> >> >> +                                     pr_warning("tuning
> >> execution
> >> >> > failed\n");
> >> >> >> +                                     continue;
> >> >> >> +                             }
> >> >> >> +
> >> >> >>                               /*
> >> >> >>                                * If controller can't handle
> bus
> >> >> width
> >> >> > test,
> >> >> >>                                * compare ext_csd previously
> read
> >> in
> >> >> 1 bit
> >> >> >> mode
> >> >> >> @@ -1056,6 +1110,15 @@ static int mmc_init_card(struct
> mmc_host
> >> >> *host,
> >> >> >> u32 ocr,
> >> >> >>                       mmc_card_set_ddr_mode(card);
> >> >> >>                       mmc_set_timing(card->host,
> >> >> MMC_TIMING_UHS_DDR50);
> >> >> >>                       mmc_set_bus_width(card->host,
> bus_width);
> >> >> >> +             } else if (hs_sdr) {
> >> >> >> +                     if (hs_sdr ==
> EXT_CSD_CARD_TYPE_SDR_1_2V) {
> >> >> >> +                             err =
> mmc_set_signal_voltage(host,
> >> >> >> +                                     MMC_SIGNAL_VOLTAGE_120,
> 0);
> >> >> >> +                             if (err)
> >> >> >> +                                     goto err;
> >> >> >> +                     }
> >> >> >> +                     mmc_set_timing(card->host,
> >> MMC_TIMING_MMC_HS);
> >> >> >> +                     mmc_set_bus_width(card->host,
> bus_width);
> >> >> >>               }
> >> >> >>       }
> >> >> >>
> >> >> >> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> >> >> >> index 1d5a3bd..c1d3ee3 100644
> >> >> >> --- a/drivers/mmc/core/sd.c
> >> >> >> +++ b/drivers/mmc/core/sd.c
> >> >> >> @@ -660,7 +660,8 @@ static int mmc_sd_init_uhs_card(struct
> >> mmc_card
> >> >> >> *card)
> >> >> >>
> >> >> >>       /* SPI mode doesn't define CMD19 */
> >> >> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
> >> >> >> >execute_tuning)
> >> >> >> -             err = card->host->ops->execute_tuning(card-
> >host);
> >> >> >> +             err = card->host->ops->execute_tuning(card-
> >host,
> >> >>   \
> >> >> >> +
> >> >> > MMC_SEND_TUNING_BLOCK);
> >> >> >>
> >> >> >>  out:
> >> >> >>       kfree(status);
> >> >> >> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
> >> >> >> index 8c04f7f..8ef8817 100644
> >> >> >> --- a/drivers/mmc/core/sdio.c
> >> >> >> +++ b/drivers/mmc/core/sdio.c
> >> >> >> @@ -14,6 +14,7 @@
> >> >> >>
> >> >> >>  #include <linux/mmc/host.h>
> >> >> >>  #include <linux/mmc/card.h>
> >> >> >> +#include <linux/mmc/mmc.h>
> >> >> >>  #include <linux/mmc/sdio.h>
> >> >> >>  #include <linux/mmc/sdio_func.h>
> >> >> >>  #include <linux/mmc/sdio_ids.h>
> >> >> >> @@ -556,7 +557,8 @@ static int mmc_sdio_init_uhs_card(struct
> >> >> mmc_card
> >> >> >> *card)
> >> >> >>
> >> >> >>       /* Initialize and start re-tuning timer */
> >> >> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
> >> >> >> >execute_tuning)
> >> >> >> -             err = card->host->ops->execute_tuning(card-
> >host);
> >> >> >> +             err = card->host->ops->execute_tuning(card-
> >host,
> >> >> >> +
> >> >> > MMC_SEND_TUNING_BLOCK);
> >> >> >>
> >> >> >>  out:
> >> >> >>
> >> >> >> diff --git a/drivers/mmc/host/sdhci.c
> b/drivers/mmc/host/sdhci.c
> >> >> >> index a7c2311..13d74bb 100644
> >> >> >> --- a/drivers/mmc/host/sdhci.c
> >> >> >> +++ b/drivers/mmc/host/sdhci.c
> >> >> >> @@ -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
> >> >> >> @@ -1016,7 +1016,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
> >> */
> >> >> >> @@ -1673,7 +1674,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;
> >> >> >> @@ -1694,10 +1695,13 @@ static int sdhci_execute_tuning(struct
> >> >> mmc_host
> >> >> >> *mmc)
> >> >> >>        * Host Controller needs tuning only in case of SDR104
> mode
> >> >> >>        * and for SDR50 mode when Use Tuning for SDR50 is set
> in
> >> >> >>        * Capabilities register.
> >> >> >> +      * If the Host Controller supports the HS200 mode then
> >> tuning
> >> >> >> +      * function has to be executed.
> >> >> >>        */
> >> >> >>       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)))
> >> >> >> +         (host->flags & SDHCI_SDR50_NEEDS_TUNING)) ||
> >> >> >> +         (host->flags & SDHCI_HS200_NEEDS_TUNING))
> >> >> >>               ctrl |= SDHCI_CTRL_EXEC_TUNING;
> >> >> >>       else {
> >> >> >>               spin_unlock(&host->lock);
> >> >> >> @@ -1733,7 +1737,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;
> >> >> >> @@ -1748,7 +1752,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.
> >> >> >> @@ -2131,12 +2145,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;
> >> >> >> @@ -2741,6 +2757,10 @@ int sdhci_add_host(struct sdhci_host
> >> *host)
> >> >> >>       if (caps[1] & SDHCI_USE_SDR50_TUNING)
> >> >> >>               host->flags |= SDHCI_SDR50_NEEDS_TUNING;
> >> >> >>
> >> >> >> +     /* Does the host needs 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;
> >> >> >> diff --git a/include/linux/mmc/card.h
> b/include/linux/mmc/card.h
> >> >> >> index 534974c..e76f649 100644
> >> >> >> --- a/include/linux/mmc/card.h
> >> >> >> +++ b/include/linux/mmc/card.h
> >> >> >> @@ -209,6 +209,7 @@ struct mmc_card {
> >> >> >>  #define MMC_STATE_HIGHSPEED_DDR (1<<4)               /* card
> is
> >> in
> >> >> high
> >> >> >> speed mode */
> >> >> >>  #define MMC_STATE_ULTRAHIGHSPEED (1<<5)              /* card
> is
> >> in
> >> >> ultra
> >> >> >> high speed mode */
> >> >> >>  #define MMC_CARD_SDXC                (1<<6)          /* card
> is
> >> >> SDXC */
> >> >> >> +#define MMC_STATE_HIGHSPEED_200      (1<<7)  /* card is in
> HS200
> >> >> >> mode */
> >> >> >>       unsigned int            quirks;         /* card quirks
> */
> >> >> >>  #define MMC_QUIRK_LENIENT_FN0        (1<<0)          /* allow
> >> SDIO
> >> >> FN0
> >> >> >> writes outside of the VS CCCR range */
> >> >> >>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func-
> >> >> >> >cur_blksize */
> >> >> >> @@ -365,6 +366,7 @@ static inline void __maybe_unused
> >> >> >> remove_quirk(struct mmc_card *card, int data)
> >> >> >>  #define mmc_card_present(c)  ((c)->state & MMC_STATE_PRESENT)
> >> >> >>  #define mmc_card_readonly(c) ((c)->state &
> MMC_STATE_READONLY)
> >> >> >>  #define mmc_card_highspeed(c)        ((c)->state &
> >> >> MMC_STATE_HIGHSPEED)
> >> >> >> +#define mmc_card_hs200(c)    ((c)->state &
> >> MMC_STATE_HIGHSPEED_200)
> >> >> >>  #define mmc_card_blockaddr(c)        ((c)->state &
> >> >> MMC_STATE_BLOCKADDR)
> >> >> >>  #define mmc_card_ddr_mode(c) ((c)->state &
> >> MMC_STATE_HIGHSPEED_DDR)
> >> >> >>  #define mmc_card_uhs(c)              ((c)->state &
> >> >> >> MMC_STATE_ULTRAHIGHSPEED)
> >> >> >> @@ -374,6 +376,7 @@ static inline void __maybe_unused
> >> >> >> remove_quirk(struct mmc_card *card, int data)
> >> >> >>  #define mmc_card_set_present(c)      ((c)->state |=
> >> >> MMC_STATE_PRESENT)
> >> >> >>  #define mmc_card_set_readonly(c) ((c)->state |=
> >> MMC_STATE_READONLY)
> >> >> >>  #define mmc_card_set_highspeed(c) ((c)->state |=
> >> >> MMC_STATE_HIGHSPEED)
> >> >> >> +#define mmc_card_set_hs200(c)        ((c)->state |=
> >> >> >> MMC_STATE_HIGHSPEED_200)
> >> >> >>  #define mmc_card_set_blockaddr(c) ((c)->state |=
> >> >> MMC_STATE_BLOCKADDR)
> >> >> >>  #define mmc_card_set_ddr_mode(c) ((c)->state |=
> >> >> >> MMC_STATE_HIGHSPEED_DDR)
> >> >> >>  #define mmc_card_set_uhs(c) ((c)->state |=
> >> >> MMC_STATE_ULTRAHIGHSPEED)
> >> >> >> diff --git a/include/linux/mmc/host.h
> b/include/linux/mmc/host.h
> >> >> >> index 706f722..5eac57a 100644
> >> >> >> --- a/include/linux/mmc/host.h
> >> >> >> +++ b/include/linux/mmc/host.h
> >> >> >> @@ -50,6 +50,7 @@ struct mmc_ios {
> >> >> >>
> >> >> >>  #define MMC_TIMING_LEGACY    0
> >> >> >>  #define MMC_TIMING_MMC_HS    1
> >> >> >> +#define MMC_TIMING_MMC_HS200 2
> >> >> >>  #define MMC_TIMING_SD_HS     2
> >> >> >>  #define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY
> >> >> >>  #define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS
> >> >> >> @@ -60,6 +61,8 @@ struct mmc_ios {
> >> >> >>  #define MMC_SDR_MODE         0
> >> >> >>  #define MMC_1_2V_DDR_MODE    1
> >> >> >>  #define MMC_1_8V_DDR_MODE    2
> >> >> >> +#define MMC_1_2V_SDR_MODE    3
> >> >> >> +#define MMC_1_8V_SDR_MODE    4
> >> >> >>
> >> >> >>       unsigned char   signal_voltage;         /* signalling
> >> voltage
> >> >> >> (1.8V or 3.3V) */
> >> >> >>
> >> >> >> @@ -148,7 +151,9 @@ struct mmc_host_ops {
> >> >> >>       void    (*init_card)(struct mmc_host *host, struct
> mmc_card
> >> >> *card);
> >> >> >>
> >> >> >>       int     (*start_signal_voltage_switch)(struct mmc_host
> >> *host,
> >> >> >> struct mmc_ios *ios);
> >> >> >> -     int     (*execute_tuning)(struct mmc_host *host);
> >> >> >> +
> >> >> >> +     /* The tuning command opcode value is different for SD
> and
> >> >> eMMC
> >> >> >> cards */
> >> >> >> +     int     (*execute_tuning)(struct mmc_host *host, u32
> >> opcode);
> >> >> >>       void    (*enable_preset_value)(struct mmc_host *host,
> bool
> >> >> enable);
> >> >> >>       int     (*select_drive_strength)(unsigned int max_dtr,
> int
> >> >> >> host_drv, int card_drv);
> >> >> >>       void    (*hw_reset)(struct mmc_host *host);
> >> >> >> @@ -242,6 +247,10 @@ struct mmc_host {
> >> >> >>  #define MMC_CAP2_CACHE_CTRL  (1 << 1)        /* Allow cache
> >> control
> >> >> */
> >> >> >>  #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)    /* Notify
> poweroff
> >> >> >> supported */
> >> >> >>  #define MMC_CAP2_NO_MULTI_READ       (1 << 3)        /*
> >> Multiblock
> >> >> reads
> >> >> >> don't work */
> >> >> >> +#define MMC_CAP2_HS200_1_8V_SDR      (1 << 4)        /* can
> >> support
> >> >> */
> >> >> >> +#define MMC_CAP2_HS200_1_2V_SDR      (1 << 5)        /* can
> >> support
> >> >> */
> >> >> >> +#define MMC_CAP2_HS200               (MMC_CAP2_HS200_1_8V_SDR
> |
> >> \
> >> >> >> +                              MMC_CAP2_HS200_1_2V_SDR)
> >> >> >>
> >> >> >>       mmc_pm_flag_t           pm_caps;        /* supported pm
> >> >> features */
> >> >> >>       unsigned int        power_notify_type;
> >> >> >> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> >> >> >> index 0e71356..7996272 100644
> >> >> >> --- a/include/linux/mmc/mmc.h
> >> >> >> +++ b/include/linux/mmc/mmc.h
> >> >> >> @@ -51,6 +51,7 @@
> >> >> >>  #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data
> addr
> >> R1
> >> >> >> */
> >> >> >>  #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data
> addr
> >> R1
> >> >> >> */
> >> >> >>  #define MMC_SEND_TUNING_BLOCK    19   /* adtc
> >>  R1
> >> >> >> */
> >> >> >> +#define MMC_SEND_TUNING_BLOCK_HS200  21      /* adtc R1  */
> >> >> >>
> >> >> >>    /* class 3 */
> >> >> >>  #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data
> addr
> >> R1
> >> >> >> */
> >> >> >> @@ -333,13 +334,76 @@ struct _mmc_csd {
> >> >> >>
> >> >> >>  #define EXT_CSD_CARD_TYPE_26 (1<<0)  /* Card can run at 26MHz
> */
> >> >> >>  #define EXT_CSD_CARD_TYPE_52 (1<<1)  /* Card can run at 52MHz
> */
> >> >> >> -#define EXT_CSD_CARD_TYPE_MASK       0xF     /* Mask out
> >> reserved
> >> >> bits */
> >> >> >> +#define EXT_CSD_CARD_TYPE_MASK       0x3F    /* Mask out
> >> reserved
> >> >> bits */
> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run
> at
> >> >> 52MHz
> >> >> >> */
> >> >> >>                                            /* DDR mode @1.8V
> or
> >> 3V
> >> >> I/O */
> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run
> at
> >> >> 52MHz
> >> >> >> */
> >> >> >>                                            /* DDR mode @1.2V
> I/O
> >> */
> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_52
> >> (EXT_CSD_CARD_TYPE_DDR_1_8V
> >> >>  \
> >> >> >>                                       |
> >> EXT_CSD_CARD_TYPE_DDR_1_2V)
> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V   (1<<4)  /* Card can run
> at
> >> >> >> 200MHz */
> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V   (1<<5)  /* Card can run
> at
> >> >> >> 200MHz */
> >> >> >> +                                             /* SDR mode
> @1.2V
> >> I/O
> >> >> */
> >> >> >> +
> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_200
>  (EXT_CSD_CARD_TYPE_SDR_1_8V
> >> >>   \
> >> >> >> +                                     |
> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
> >> >> >> +
> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL
>  (EXT_CSD_CARD_TYPE_SDR_200
> >> >>  \
> >> >> >> +                                     | EXT_CSD_CARD_TYPE_52
> >> >>  \
> >> >> >> +                                     | EXT_CSD_CARD_TYPE_26)
> >> >> >> +
> >> >> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_2V_ALL
> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V     \
> >> >> >> +                                     | EXT_CSD_CARD_TYPE_52
> >> >>  \
> >> >> >> +                                     | EXT_CSD_CARD_TYPE_26)
> >> >> >> +
> >> >> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_8V_ALL
> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V     \
> >> >> >> +                                     | EXT_CSD_CARD_TYPE_52
> >> >>  \
> >> >> >> +                                     | EXT_CSD_CARD_TYPE_26)
> >> >> >> +
> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V
> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
> >> >> > \
> >> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_52
> >> >> > \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> +
> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V
> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
> >> >> > \
> >> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_52
> >> >> > \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> +
> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V
> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
> >> >> > \
> >> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_52
> >> >> > \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> +
> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V
> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
> >> >> > \
> >> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_52
> >> >> > \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> +
> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52
> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_DDR_52
> >> >> > \
> >> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_52
> >> >> > \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> +
> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52
> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_DDR_52
> >> >> > \
> >> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_52
> >> >> > \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> +
> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V
> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
> >> >> > \
> >> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_52
> >> >> > \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> +
> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V
> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
> >> >> > \
> >> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_52
> >> >> > \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> +
> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52
> >> >> (EXT_CSD_CARD_TYPE_SDR_200
> >> >> >> \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_DDR_52
> >> >> > \
> >> >> >> +                                             |
> >> EXT_CSD_CARD_TYPE_52
> >> >> > \
> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >>
> >> >> >>  #define EXT_CSD_BUS_WIDTH_1  0       /* Card is in 1 bit mode
> */
> >> >> >>  #define EXT_CSD_BUS_WIDTH_4  1       /* Card is in 4 bit mode
> */
> >> >> >> diff --git a/include/linux/mmc/sdhci.h
> >> b/include/linux/mmc/sdhci.h
> >> >> >> index e4b6935..d9a2222 100644
> >> >> >> --- a/include/linux/mmc/sdhci.h
> >> >> >> +++ b/include/linux/mmc/sdhci.h
> >> >> >> @@ -121,6 +121,7 @@ struct sdhci_host {
> >> >> >>  #define SDHCI_AUTO_CMD23     (1<<7)  /* Auto CMD23 support */
> >> >> >>  #define SDHCI_PV_ENABLED     (1<<8)  /* Preset value enabled
> */
> >> >> >>  #define SDHCI_SDIO_IRQ_ENABLED       (1<<9)  /* SDIO irq
> enabled
> >> */
> >> >> >> +#define SDHCI_HS200_NEEDS_TUNING (1<<10)     /* HS200 needs
> >> tuning
> >> >> */
> >> >> >>
> >> >> >>       unsigned int version;   /* SDHCI spec. version */
> >> >> >>
> >> >> >> --
> >> >> >> 1.7.1
> >> >> >>
> >> >> >> --
> >> >> >> To unsubscribe from this list: send the line "unsubscribe
> linux-
> >> mmc"
> >> >> in
> >> >> >> the body of a message to majordomo@vger.kernel.org
> >> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
> >> info.html
> >> >> >
> >> >> > --
> >> >> > To unsubscribe from this list: send the line "unsubscribe
> linux-
> >> mmc"
> >> >> in
> >> >> > the body of a message to majordomo@vger.kernel.org
> >> >> > More majordomo info at  http://vger.kernel.org/majordomo-
> info.html
> >> >> >
> >> >> --
> >> >> To unsubscribe from this list: send the line "unsubscribe linux-
> mmc"
> >> in
> >> >> the body of a message to majordomo@vger.kernel.org
> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
> info.html
> >> >
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc"
> in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
Girish K S Dec. 5, 2011, 6:50 a.m. UTC | #8
On 5 December 2011 11:46, Subhash Jadavani <subhashj@codeaurora.org> wrote:
>
>
>> -----Original Message-----
>> From: Girish K S [mailto:girish.shivananjappa@linaro.org]
>> Sent: Friday, December 02, 2011 5:08 PM
>> To: Subhash Jadavani
>> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>> soc@vger.kernel.org; Chris Ball
>> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>>
>> On 2 December 2011 00:02, Subhash Jadavani <subhashj@codeaurora.org>
>> wrote:
>> >
>> >
>> >> -----Original Message-----
>> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>> >> owner@vger.kernel.org] On Behalf Of Girish K S
>> >> Sent: Thursday, December 01, 2011 7:48 PM
>> >> To: Subhash Jadavani
>> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>> >> soc@vger.kernel.org; Chris Ball
>> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>> >>
>> >> On 1 December 2011 16:27, Subhash Jadavani <subhashj@codeaurora.org>
>> >> wrote:
>> >> >
>> >> >
>> >> >> -----Original Message-----
>> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
>> >> >> Sent: Thursday, December 01, 2011 3:58 PM
>> >> >> To: Subhash Jadavani
>> >> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>> >> >> soc@vger.kernel.org; Chris Ball
>> >> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC
>> 4.5
>> >> >>
>> >> >> On 1 December 2011 15:33, Subhash Jadavani
>> <subhashj@codeaurora.org>
>> >> >> wrote:
>> >> >> > Hi Girish,
>> >> >> >
>> >> >> >> -----Original Message-----
>> >> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>> >> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
>> >> >> >> Sent: Wednesday, November 30, 2011 2:24 PM
>> >> >> >> To: linux-mmc@vger.kernel.org
>> >> >> >> Cc: patches@linaro.org; linux-samsung-soc@vger.kernel.org;
>> >> >> >> subhashj@codeaurora.org; Girish K S; Chris Ball
>> >> >> >> Subject: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>> >> >> >>
>> >> >> >> This patch adds the support of the HS200 bus speed for eMMC
>> 4.5
>> >> >> >> devices.
>> >> >> >> The eMMC 4.5 devices have support for 200MHz bus speed.The mmc
>> >> core
>> >> >> and
>> >> >> >> host modules have been touched to add support for this module.
>> >> >> >>
>> >> >> >> It is necessary to know the card type in the sdhci.c file to
>> add
>> >> >> >> support
>> >> >> >> for eMMC tuning function. So card.h file is included to import
>> >> the
>> >> >> card
>> >> >> >> data structure.
>> >> >> >>
>> >> >> >> cc: Chris Ball <cjb@laptop.org>
>> >> >> >> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
>> >> >> >> ---
>> >> >> >> Changes in v5:
>> >> >> >>       Reduced the case statements for better code readability.
>> >> >> Removed
>> >> >> >>       unused macro definitions. Modified the tuning function
>> >> >> prototype
>> >> >> >>       and definition to support tuning for both SD and eMMC
>> >> cards.
>> >> >> >> Changes in v4:
>> >> >> >>       Rebased onto chris-mmc/mmc-next branch. This patch is
>> >> >> >> successfully
>> >> >> >>       applied on commit with id
>> >> >> >> de022ed3fdc14808299b2fa66dbb1ed5ab921912.
>> >> >> >> Changes in v3:
>> >> >> >>       In the previous commits of chris-mmc/mmc-next branch,
>> the
>> >> >> patch
>> >> >> >> with
>> >> >> >>       commit id (c0f22a2c92e357e7cb3988b0b13034d70b7461f9)
>> >> defines
>> >> >> >> caps2 for
>> >> >> >>       more capabilities. This patch version deletes the member
>> >> >> >> ext_caps(created
>> >> >> >>       in my earlier patch) from struct mmc_host and reuses
>> >> already
>> >> >> >> accepted
>> >> >> >>       caps2 member.
>> >> >> >> Changes in v2:
>> >> >> >>       Rebased to latest chris-mmc/mmc-next branch. Resolved
>> >> >> indentation
>> >> >> >>       problems identified in review. This patch has to be
>> applied
>> >> >> >> before
>> >> >> >>       the patch released for modifying the printk messages.
>> >> >> >> Changes in v1:
>> >> >> >>       Case statements in switch that produce same result have
>> >> >> >>       been combined to reduce repeated assignments.
>> >> >> >>       patch recreated after rebase to chris balls mmc-next
>> >> branch.
>> >> >> >>
>> >> >> >>  drivers/mmc/core/bus.c    |    3 +-
>> >> >> >>  drivers/mmc/core/mmc.c    |   77
>> >> >> >> ++++++++++++++++++++++++++++++++++++++++----
>> >> >> >>  drivers/mmc/core/sd.c     |    3 +-
>> >> >> >>  drivers/mmc/core/sdio.c   |    4 ++-
>> >> >> >>  drivers/mmc/host/sdhci.c  |   38 +++++++++++++++++-----
>> >> >> >>  include/linux/mmc/card.h  |    3 ++
>> >> >> >>  include/linux/mmc/host.h  |   11 ++++++-
>> >> >> >>  include/linux/mmc/mmc.h   |   66
>> >> >> >> ++++++++++++++++++++++++++++++++++++++-
>> >> >> >>  include/linux/mmc/sdhci.h |    1 +
>> >> >> >>  9 files changed, 185 insertions(+), 21 deletions(-)
>> >> >> >>
>> >> >> >> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> >> >> >> index 5639fdf..83c9f8d 100644
>> >> >> >> --- a/drivers/mmc/core/bus.c
>> >> >> >> +++ b/drivers/mmc/core/bus.c
>> >> >> >> @@ -301,10 +301,11 @@ int mmc_add_card(struct mmc_card *card)
>> >> >> >>                       mmc_card_ddr_mode(card) ? "DDR " : "",
>> >> >> >>                       type);
>> >> >> >>       } else {
>> >> >> >> -             printk(KERN_INFO "%s: new %s%s%s card at address
>> >> >> %04x\n",
>> >> >> >> +             pr_info("%s: new %s%s%s%s card at address
>> %04x\n",
>> >> >> >>                       mmc_hostname(card->host),
>> >> >> >>                       mmc_card_uhs(card) ? "ultra high speed "
>> :
>> >> >> >>                       (mmc_card_highspeed(card) ? "high speed
>> " :
>> >> >> ""),
>> >> >> >> +                     (mmc_card_hs200(card) ? "HS200 " : ""),
>> >> >> >>                       mmc_card_ddr_mode(card) ? "DDR " : "",
>> >> >> >>                       type, card->rca);
>> >> >> >>       }
>> >> >> >> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> >> >> >> index a1223bd..f4124d6 100644
>> >> >> >> --- a/drivers/mmc/core/mmc.c
>> >> >> >> +++ b/drivers/mmc/core/mmc.c
>> >> >> >> @@ -285,6 +285,27 @@ static int mmc_read_ext_csd(struct
>> mmc_card
>> >> >> *card,
>> >> >> >> u8 *ext_csd)
>> >> >> >>       }
>> >> >> >>       card->ext_csd.raw_card_type =
>> ext_csd[EXT_CSD_CARD_TYPE];
>> >> >> >>       switch (ext_csd[EXT_CSD_CARD_TYPE] &
>> >> EXT_CSD_CARD_TYPE_MASK) {
>> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL:
>> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
>> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
>> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
>> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
>> >> >> >> +             card->ext_csd.card_type =
>> >> EXT_CSD_CARD_TYPE_SDR_200;
>> >> >> >> +             break;
>> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
>> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
>> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
>> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
>> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
>> >> >> >> +             card->ext_csd.card_type =
>> >> EXT_CSD_CARD_TYPE_SDR_1_2V;
>> >> >> >> +             break;
>> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
>> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
>> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
>> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
>> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
>> >> >> >> +             card->ext_csd.card_type =
>> >> EXT_CSD_CARD_TYPE_SDR_1_8V;
>> >> >> >> +             break;
>> >> >> >>       case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
>> >> >> >>            EXT_CSD_CARD_TYPE_26:
>> >> >> >>               card->ext_csd.hs_max_dtr = 52000000;
>> >> >> >> @@ -699,6 +720,7 @@ static int mmc_init_card(struct mmc_host
>> >> *host,
>> >> >> u32
>> >> >> >> ocr,
>> >> >> >>  {
>> >> >> >>       struct mmc_card *card;
>> >> >> >>       int err, ddr = 0;
>> >> >> >> +     int hs_sdr = 0;
>> >> >> >>       u32 cid[4];
>> >> >> >>       unsigned int max_dtr;
>> >> >> >>       u32 rocr;
>> >> >> >> @@ -894,11 +916,16 @@ static int mmc_init_card(struct mmc_host
>> >> >> *host,
>> >> >> >> u32 ocr,
>> >> >> >>       /*
>> >> >> >>        * Activate high speed (if supported)
>> >> >> >>        */
>> >> >> >> -     if ((card->ext_csd.hs_max_dtr != 0) &&
>> >> >> >> -             (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
>> >> >> >> -             err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> >> >> -                              EXT_CSD_HS_TIMING, 1,
>> >> >> >> -                              card-
>> >ext_csd.generic_cmd6_time);
>> >> >> >> +     if (card->ext_csd.hs_max_dtr != 0) {
>> >> >> >> +             err = 0;
>> >> >> >> +             if ((card->ext_csd.hs_max_dtr > 52000000) &&
>> >> >> >> +                 (host->caps2 & MMC_CAP2_HS200))
>> >> >> >> +                     err = mmc_switch(card,
>> >> EXT_CSD_CMD_SET_NORMAL,
>> >> >> >> +                                      EXT_CSD_HS_TIMING, 2,
>> 0);
>> >> >> >> +             else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
>> >> >> >> +                     err = mmc_switch(card,
>> >> EXT_CSD_CMD_SET_NORMAL,
>> >> >> >> +                                      EXT_CSD_HS_TIMING, 1,
>> 0);
>> >> >> >> +
>> >> >> >>               if (err && err != -EBADMSG)
>> >> >> >>                       goto free_card;
>> >> >> >>
>> >> >> >> @@ -907,7 +934,11 @@ static int mmc_init_card(struct mmc_host
>> >> *host,
>> >> >> >> u32 ocr,
>> >> >> >>                              mmc_hostname(card->host));
>> >> >> >>                       err = 0;
>> >> >> >>               } else {
>> >> >> >> -                     mmc_card_set_highspeed(card);
>> >> >> >> +                     if ((card->ext_csd.hs_max_dtr >
>> 52000000)
>> >> &&
>> >> >> >> +                         (host->caps2 & MMC_CAP2_HS200))
>> >> >> >> +                             mmc_card_set_hs200(card);
>> >> >> >> +                     else
>> >> >> >> +                             mmc_card_set_highspeed(card);
>> >> >> >>                       mmc_set_timing(card->host,
>> >> MMC_TIMING_MMC_HS);
>> >> >> >
>> >> >> > MMC_TIMING_MMC_HS200 is defined but still not used.
>> >> >> >
>> >> >> > So I guess it should be like this ::
>> >> >> >  +                      if ((card->ext_csd.hs_max_dtr >
>> 52000000)
>> >> &&
>> >> >> >  +                          (host->caps2 & MMC_CAP2_HS200)) {
>> >> >> >  +                              mmc_card_set_hs200(card);
>> >> >> >  +                      mmc_set_timing(card->host,
>> >> >> MMC_TIMING_MMC_HS200)
>> >> >> >  +                      } else {
>> >> >> >  +                              mmc_card_set_highspeed(card);
>> >> >> >  +                              mmc_set_timing(card->host,
>> >> >> > MMC_TIMING_MMC_HS)
>> >> >> >  +                      }
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> >>               }
>> >> >> >>       }
>> >> >> >> @@ -933,7 +964,7 @@ static int mmc_init_card(struct mmc_host
>> >> *host,
>> >> >> u32
>> >> >> >> ocr,
>> >> >> >>        */
>> >> >> >>       max_dtr = (unsigned int)-1;
>> >> >> >>
>> >> >> >> -     if (mmc_card_highspeed(card)) {
>> >> >> >> +     if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
>> >> >> >>               if (max_dtr > card->ext_csd.hs_max_dtr)
>> >> >> >>                       max_dtr = card->ext_csd.hs_max_dtr;
>> >> >> >>       } else if (max_dtr > card->csd.max_dtr) {
>> >> >> >> @@ -959,6 +990,18 @@ static int mmc_init_card(struct mmc_host
>> >> *host,
>> >> >> >> u32 ocr,
>> >> >> >>       }
>> >> >> >>
>> >> >> >>       /*
>> >> >> >> +      * Indicate HS200 SDR mode (if supported).
>> >> >> >> +      */
>> >> >> >> +     if (mmc_card_hs200(card)) {
>> >> >> >> +             if ((card->ext_csd.card_type &
>> >> >> EXT_CSD_CARD_TYPE_SDR_1_8V)
>> >> >> >> +                     && (host->caps2 &
>> MMC_CAP2_HS200_1_8V_SDR))
>> >> >> >> +                             hs_sdr = MMC_1_8V_SDR_MODE;
>> >> >> >> +             else if ((card->ext_csd.card_type &
>> >> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
>> >> >> >> +                     && (host->caps2 &
>> MMC_CAP2_HS200_1_2V_SDR))
>> >> >> >> +                             hs_sdr = MMC_1_2V_SDR_MODE;
>> >> >> >> +     }
>> >> >> >> +
>> >> >> >> +     /*
>> >> >> >>        * Activate wide bus and DDR (if supported).
>> >> >> >>        */
>> >> >> >>       if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
>> >> >> >> @@ -998,6 +1041,17 @@ static int mmc_init_card(struct mmc_host
>> >> >> *host,
>> >> >> >> u32 ocr,
>> >> >> >>                       if (!err) {
>> >> >> >>                               mmc_set_bus_width(card->host,
>> >> >> bus_width);
>> >> >> >>
>> >> >> >> +                             if ((host->caps2 &
>> MMC_CAP2_HS200)
>> >> &&
>> >> >> >> +                                 card->host->ops-
>> >> >execute_tuning)
>> >> >> >> +                                     err = card->host->ops->
>> \
>> >> >> >> +
>> execute_tuning(card-
>> >> >> >host,
>> >> >> >> +
>> >> >> > MMC_SEND_TUNING_BLOCK_HS200);
>> >> >> >
>> >> >> >
>> >> >> > execute_tuning should be done right after the timing is changed
>> to
>> >> >> HS200 and
>> >> >> > clock rate is changed to 200Mhz. This is not the correct
>> sequence
>> >> to
>> >> >> call
>> >> >> > the execute_tuning().
>> >> >> > As told earlier, It is mentioned in the spec that tuning should
>> be
>> >> >> executed after change of buswidth (mandatory). Also it mentions
>> that
>> >> >> "The host may invoke the HS200 tuning sequence, by sending CMD21
>> to
>> >> the
>> >> >> device". It means that
>> >> >>  after setting the HS200 mode, Changing to freq > 52Mhz and
>> changing
>> >> >> the bus width tuning can be executed anytime to identify the
>> >> sampling
>> >> >> point to read.(By anytime i mean before actual block read
>> >> Operation).
>> >> >> Can you please point me to the place in the spec where it
>> specifies
>> >> >> tuning should be done immediately after freq change (may be i
>> missed
>> >> >> to read it).
>> >> >
>> >> >
>> >> > Ok. let me ask you this. Why do we run the execute_tuning()? It's
>> to
>> >> tune
>> >> > the sampling clock generator of host controller before you start
>> any
>> >> read
>> >> > operation (on command line or data line) from card. If you don't
>> tune
>> >> the
>> >> > sampling clock generator before the read operation (after changing
>> >> the
>> >> > timing to HS200 and clock rate to 200mhz), you can't be sure that
>> >> read
>> >> > operation from card will be completed without errors. You may get
>> the
>> >> data /
>> >> > cmd response CRC errors. At least this will surely fail on our MSM
>> >> SDCC host
>> >> > controller. That's what we had faced with SD3.0 UHS-I tuning as
>> well
>> >> as
>> >> > mentioned in http://www.spinics.net/lists/linux-arm-
>> >> msm/msg03867.html.
>> >
>> >> > this tuning is done before any read opration for the best bus
>> width
>> >> supported.
>> > Agreed. But can we be sure that "command response" for bus width
>> change via
>> > CMD6, will not have any command CRC failures if tuning is not done?
>> All responses are sent on CMD line not on data lines, And sampling is
>> done for Data lines before reading. So command CRC failure doesnt
>> depend on tuning. If you get error during CMD6 it could be that device
>> cannot support the bus width at the set frequency.
>
> I guess it's not the correct assumption here. Sampling point tuning is to
Its Not assumption "Specification says responses are all sent on CMD only"
> tune the sampling point for data received on both CMD and DATA lines (not
> just data lines). I can't find detailed mentioning of this in eMMC4.5
Pls check the section 6.6.7.1. the 2nd paragraph quotes "which in turn
uses it to find the
optimal sampling point for the data lines"
> (that's the documentation short coming, you can even confirm whether tuning
> procedure is required for CMD line or not from JEDEC) but SD3.01
> specification does mention this tuning procedure in great details. NOTE:
> eMMC4.5 HS200 mode is mostly inspired from SD3.01 UHS-I bus speed modes.
>
> Section " 4.2.4.5 Tuning Command" in "SD3.01 - Simplified
> (Part_1_Physical_Layer_Simplified_Specification_Ver_3.01_Final_100518)"
> specification(can be downloaded from here:
> https://www.sdcard.org/downloads/pls/), clearly states this:
>
> 4.2.4.5 Tuning Command
> CMD19 is defined for Send Tuning Block Command. R1 type response is defined.
> CMD19 can be
> executed in transfer state of 1.8V signaling mode while the card is
> unlocked. The other case, CMD19 is
> treated as illegal command. Data block, carried by DAT[3:0], contains a
> pattern for tuning sampling
> position to receive data on the CMD and DAT[3:0] line. The block length of
> CMD19 is fixed and CMD16
> is not required.
> I have no idea of the SD spec. I have just seen the eMMC spec and above quotes might answer your doubt
> So before tuning, you may get the Command CRC errors in HS200 mode.
>
> Regards,
> Subhash
>
>> >
>> >> ps:Chris need your comment on this
>> >> >
>> >> >> >> +
>> >> >> >> +                             if (err) {
>> >> >> >> +                                     pr_warning("tuning
>> >> execution
>> >> >> > failed\n");
>> >> >> >> +                                     continue;
>> >> >> >> +                             }
>> >> >> >> +
>> >> >> >>                               /*
>> >> >> >>                                * If controller can't handle
>> bus
>> >> >> width
>> >> >> > test,
>> >> >> >>                                * compare ext_csd previously
>> read
>> >> in
>> >> >> 1 bit
>> >> >> >> mode
>> >> >> >> @@ -1056,6 +1110,15 @@ static int mmc_init_card(struct
>> mmc_host
>> >> >> *host,
>> >> >> >> u32 ocr,
>> >> >> >>                       mmc_card_set_ddr_mode(card);
>> >> >> >>                       mmc_set_timing(card->host,
>> >> >> MMC_TIMING_UHS_DDR50);
>> >> >> >>                       mmc_set_bus_width(card->host,
>> bus_width);
>> >> >> >> +             } else if (hs_sdr) {
>> >> >> >> +                     if (hs_sdr ==
>> EXT_CSD_CARD_TYPE_SDR_1_2V) {
>> >> >> >> +                             err =
>> mmc_set_signal_voltage(host,
>> >> >> >> +                                     MMC_SIGNAL_VOLTAGE_120,
>> 0);
>> >> >> >> +                             if (err)
>> >> >> >> +                                     goto err;
>> >> >> >> +                     }
>> >> >> >> +                     mmc_set_timing(card->host,
>> >> MMC_TIMING_MMC_HS);
>> >> >> >> +                     mmc_set_bus_width(card->host,
>> bus_width);
>> >> >> >>               }
>> >> >> >>       }
>> >> >> >>
>> >> >> >> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
>> >> >> >> index 1d5a3bd..c1d3ee3 100644
>> >> >> >> --- a/drivers/mmc/core/sd.c
>> >> >> >> +++ b/drivers/mmc/core/sd.c
>> >> >> >> @@ -660,7 +660,8 @@ static int mmc_sd_init_uhs_card(struct
>> >> mmc_card
>> >> >> >> *card)
>> >> >> >>
>> >> >> >>       /* SPI mode doesn't define CMD19 */
>> >> >> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
>> >> >> >> >execute_tuning)
>> >> >> >> -             err = card->host->ops->execute_tuning(card-
>> >host);
>> >> >> >> +             err = card->host->ops->execute_tuning(card-
>> >host,
>> >> >>   \
>> >> >> >> +
>> >> >> > MMC_SEND_TUNING_BLOCK);
>> >> >> >>
>> >> >> >>  out:
>> >> >> >>       kfree(status);
>> >> >> >> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
>> >> >> >> index 8c04f7f..8ef8817 100644
>> >> >> >> --- a/drivers/mmc/core/sdio.c
>> >> >> >> +++ b/drivers/mmc/core/sdio.c
>> >> >> >> @@ -14,6 +14,7 @@
>> >> >> >>
>> >> >> >>  #include <linux/mmc/host.h>
>> >> >> >>  #include <linux/mmc/card.h>
>> >> >> >> +#include <linux/mmc/mmc.h>
>> >> >> >>  #include <linux/mmc/sdio.h>
>> >> >> >>  #include <linux/mmc/sdio_func.h>
>> >> >> >>  #include <linux/mmc/sdio_ids.h>
>> >> >> >> @@ -556,7 +557,8 @@ static int mmc_sdio_init_uhs_card(struct
>> >> >> mmc_card
>> >> >> >> *card)
>> >> >> >>
>> >> >> >>       /* Initialize and start re-tuning timer */
>> >> >> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
>> >> >> >> >execute_tuning)
>> >> >> >> -             err = card->host->ops->execute_tuning(card-
>> >host);
>> >> >> >> +             err = card->host->ops->execute_tuning(card-
>> >host,
>> >> >> >> +
>> >> >> > MMC_SEND_TUNING_BLOCK);
>> >> >> >>
>> >> >> >>  out:
>> >> >> >>
>> >> >> >> diff --git a/drivers/mmc/host/sdhci.c
>> b/drivers/mmc/host/sdhci.c
>> >> >> >> index a7c2311..13d74bb 100644
>> >> >> >> --- a/drivers/mmc/host/sdhci.c
>> >> >> >> +++ b/drivers/mmc/host/sdhci.c
>> >> >> >> @@ -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
>> >> >> >> @@ -1016,7 +1016,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
>> >> */
>> >> >> >> @@ -1673,7 +1674,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;
>> >> >> >> @@ -1694,10 +1695,13 @@ static int sdhci_execute_tuning(struct
>> >> >> mmc_host
>> >> >> >> *mmc)
>> >> >> >>        * Host Controller needs tuning only in case of SDR104
>> mode
>> >> >> >>        * and for SDR50 mode when Use Tuning for SDR50 is set
>> in
>> >> >> >>        * Capabilities register.
>> >> >> >> +      * If the Host Controller supports the HS200 mode then
>> >> tuning
>> >> >> >> +      * function has to be executed.
>> >> >> >>        */
>> >> >> >>       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)))
>> >> >> >> +         (host->flags & SDHCI_SDR50_NEEDS_TUNING)) ||
>> >> >> >> +         (host->flags & SDHCI_HS200_NEEDS_TUNING))
>> >> >> >>               ctrl |= SDHCI_CTRL_EXEC_TUNING;
>> >> >> >>       else {
>> >> >> >>               spin_unlock(&host->lock);
>> >> >> >> @@ -1733,7 +1737,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;
>> >> >> >> @@ -1748,7 +1752,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.
>> >> >> >> @@ -2131,12 +2145,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;
>> >> >> >> @@ -2741,6 +2757,10 @@ int sdhci_add_host(struct sdhci_host
>> >> *host)
>> >> >> >>       if (caps[1] & SDHCI_USE_SDR50_TUNING)
>> >> >> >>               host->flags |= SDHCI_SDR50_NEEDS_TUNING;
>> >> >> >>
>> >> >> >> +     /* Does the host needs 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;
>> >> >> >> diff --git a/include/linux/mmc/card.h
>> b/include/linux/mmc/card.h
>> >> >> >> index 534974c..e76f649 100644
>> >> >> >> --- a/include/linux/mmc/card.h
>> >> >> >> +++ b/include/linux/mmc/card.h
>> >> >> >> @@ -209,6 +209,7 @@ struct mmc_card {
>> >> >> >>  #define MMC_STATE_HIGHSPEED_DDR (1<<4)               /* card
>> is
>> >> in
>> >> >> high
>> >> >> >> speed mode */
>> >> >> >>  #define MMC_STATE_ULTRAHIGHSPEED (1<<5)              /* card
>> is
>> >> in
>> >> >> ultra
>> >> >> >> high speed mode */
>> >> >> >>  #define MMC_CARD_SDXC                (1<<6)          /* card
>> is
>> >> >> SDXC */
>> >> >> >> +#define MMC_STATE_HIGHSPEED_200      (1<<7)  /* card is in
>> HS200
>> >> >> >> mode */
>> >> >> >>       unsigned int            quirks;         /* card quirks
>> */
>> >> >> >>  #define MMC_QUIRK_LENIENT_FN0        (1<<0)          /* allow
>> >> SDIO
>> >> >> FN0
>> >> >> >> writes outside of the VS CCCR range */
>> >> >> >>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func-
>> >> >> >> >cur_blksize */
>> >> >> >> @@ -365,6 +366,7 @@ static inline void __maybe_unused
>> >> >> >> remove_quirk(struct mmc_card *card, int data)
>> >> >> >>  #define mmc_card_present(c)  ((c)->state & MMC_STATE_PRESENT)
>> >> >> >>  #define mmc_card_readonly(c) ((c)->state &
>> MMC_STATE_READONLY)
>> >> >> >>  #define mmc_card_highspeed(c)        ((c)->state &
>> >> >> MMC_STATE_HIGHSPEED)
>> >> >> >> +#define mmc_card_hs200(c)    ((c)->state &
>> >> MMC_STATE_HIGHSPEED_200)
>> >> >> >>  #define mmc_card_blockaddr(c)        ((c)->state &
>> >> >> MMC_STATE_BLOCKADDR)
>> >> >> >>  #define mmc_card_ddr_mode(c) ((c)->state &
>> >> MMC_STATE_HIGHSPEED_DDR)
>> >> >> >>  #define mmc_card_uhs(c)              ((c)->state &
>> >> >> >> MMC_STATE_ULTRAHIGHSPEED)
>> >> >> >> @@ -374,6 +376,7 @@ static inline void __maybe_unused
>> >> >> >> remove_quirk(struct mmc_card *card, int data)
>> >> >> >>  #define mmc_card_set_present(c)      ((c)->state |=
>> >> >> MMC_STATE_PRESENT)
>> >> >> >>  #define mmc_card_set_readonly(c) ((c)->state |=
>> >> MMC_STATE_READONLY)
>> >> >> >>  #define mmc_card_set_highspeed(c) ((c)->state |=
>> >> >> MMC_STATE_HIGHSPEED)
>> >> >> >> +#define mmc_card_set_hs200(c)        ((c)->state |=
>> >> >> >> MMC_STATE_HIGHSPEED_200)
>> >> >> >>  #define mmc_card_set_blockaddr(c) ((c)->state |=
>> >> >> MMC_STATE_BLOCKADDR)
>> >> >> >>  #define mmc_card_set_ddr_mode(c) ((c)->state |=
>> >> >> >> MMC_STATE_HIGHSPEED_DDR)
>> >> >> >>  #define mmc_card_set_uhs(c) ((c)->state |=
>> >> >> MMC_STATE_ULTRAHIGHSPEED)
>> >> >> >> diff --git a/include/linux/mmc/host.h
>> b/include/linux/mmc/host.h
>> >> >> >> index 706f722..5eac57a 100644
>> >> >> >> --- a/include/linux/mmc/host.h
>> >> >> >> +++ b/include/linux/mmc/host.h
>> >> >> >> @@ -50,6 +50,7 @@ struct mmc_ios {
>> >> >> >>
>> >> >> >>  #define MMC_TIMING_LEGACY    0
>> >> >> >>  #define MMC_TIMING_MMC_HS    1
>> >> >> >> +#define MMC_TIMING_MMC_HS200 2
>> >> >> >>  #define MMC_TIMING_SD_HS     2
>> >> >> >>  #define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY
>> >> >> >>  #define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS
>> >> >> >> @@ -60,6 +61,8 @@ struct mmc_ios {
>> >> >> >>  #define MMC_SDR_MODE         0
>> >> >> >>  #define MMC_1_2V_DDR_MODE    1
>> >> >> >>  #define MMC_1_8V_DDR_MODE    2
>> >> >> >> +#define MMC_1_2V_SDR_MODE    3
>> >> >> >> +#define MMC_1_8V_SDR_MODE    4
>> >> >> >>
>> >> >> >>       unsigned char   signal_voltage;         /* signalling
>> >> voltage
>> >> >> >> (1.8V or 3.3V) */
>> >> >> >>
>> >> >> >> @@ -148,7 +151,9 @@ struct mmc_host_ops {
>> >> >> >>       void    (*init_card)(struct mmc_host *host, struct
>> mmc_card
>> >> >> *card);
>> >> >> >>
>> >> >> >>       int     (*start_signal_voltage_switch)(struct mmc_host
>> >> *host,
>> >> >> >> struct mmc_ios *ios);
>> >> >> >> -     int     (*execute_tuning)(struct mmc_host *host);
>> >> >> >> +
>> >> >> >> +     /* The tuning command opcode value is different for SD
>> and
>> >> >> eMMC
>> >> >> >> cards */
>> >> >> >> +     int     (*execute_tuning)(struct mmc_host *host, u32
>> >> opcode);
>> >> >> >>       void    (*enable_preset_value)(struct mmc_host *host,
>> bool
>> >> >> enable);
>> >> >> >>       int     (*select_drive_strength)(unsigned int max_dtr,
>> int
>> >> >> >> host_drv, int card_drv);
>> >> >> >>       void    (*hw_reset)(struct mmc_host *host);
>> >> >> >> @@ -242,6 +247,10 @@ struct mmc_host {
>> >> >> >>  #define MMC_CAP2_CACHE_CTRL  (1 << 1)        /* Allow cache
>> >> control
>> >> >> */
>> >> >> >>  #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)    /* Notify
>> poweroff
>> >> >> >> supported */
>> >> >> >>  #define MMC_CAP2_NO_MULTI_READ       (1 << 3)        /*
>> >> Multiblock
>> >> >> reads
>> >> >> >> don't work */
>> >> >> >> +#define MMC_CAP2_HS200_1_8V_SDR      (1 << 4)        /* can
>> >> support
>> >> >> */
>> >> >> >> +#define MMC_CAP2_HS200_1_2V_SDR      (1 << 5)        /* can
>> >> support
>> >> >> */
>> >> >> >> +#define MMC_CAP2_HS200               (MMC_CAP2_HS200_1_8V_SDR
>> |
>> >> \
>> >> >> >> +                              MMC_CAP2_HS200_1_2V_SDR)
>> >> >> >>
>> >> >> >>       mmc_pm_flag_t           pm_caps;        /* supported pm
>> >> >> features */
>> >> >> >>       unsigned int        power_notify_type;
>> >> >> >> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> >> >> >> index 0e71356..7996272 100644
>> >> >> >> --- a/include/linux/mmc/mmc.h
>> >> >> >> +++ b/include/linux/mmc/mmc.h
>> >> >> >> @@ -51,6 +51,7 @@
>> >> >> >>  #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data
>> addr
>> >> R1
>> >> >> >> */
>> >> >> >>  #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data
>> addr
>> >> R1
>> >> >> >> */
>> >> >> >>  #define MMC_SEND_TUNING_BLOCK    19   /* adtc
>> >>  R1
>> >> >> >> */
>> >> >> >> +#define MMC_SEND_TUNING_BLOCK_HS200  21      /* adtc R1  */
>> >> >> >>
>> >> >> >>    /* class 3 */
>> >> >> >>  #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data
>> addr
>> >> R1
>> >> >> >> */
>> >> >> >> @@ -333,13 +334,76 @@ struct _mmc_csd {
>> >> >> >>
>> >> >> >>  #define EXT_CSD_CARD_TYPE_26 (1<<0)  /* Card can run at 26MHz
>> */
>> >> >> >>  #define EXT_CSD_CARD_TYPE_52 (1<<1)  /* Card can run at 52MHz
>> */
>> >> >> >> -#define EXT_CSD_CARD_TYPE_MASK       0xF     /* Mask out
>> >> reserved
>> >> >> bits */
>> >> >> >> +#define EXT_CSD_CARD_TYPE_MASK       0x3F    /* Mask out
>> >> reserved
>> >> >> bits */
>> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run
>> at
>> >> >> 52MHz
>> >> >> >> */
>> >> >> >>                                            /* DDR mode @1.8V
>> or
>> >> 3V
>> >> >> I/O */
>> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run
>> at
>> >> >> 52MHz
>> >> >> >> */
>> >> >> >>                                            /* DDR mode @1.2V
>> I/O
>> >> */
>> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_52
>> >> (EXT_CSD_CARD_TYPE_DDR_1_8V
>> >> >>  \
>> >> >> >>                                       |
>> >> EXT_CSD_CARD_TYPE_DDR_1_2V)
>> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V   (1<<4)  /* Card can run
>> at
>> >> >> >> 200MHz */
>> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V   (1<<5)  /* Card can run
>> at
>> >> >> >> 200MHz */
>> >> >> >> +                                             /* SDR mode
>> @1.2V
>> >> I/O
>> >> >> */
>> >> >> >> +
>> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_200
>>  (EXT_CSD_CARD_TYPE_SDR_1_8V
>> >> >>   \
>> >> >> >> +                                     |
>> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
>> >> >> >> +
>> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL
>>  (EXT_CSD_CARD_TYPE_SDR_200
>> >> >>  \
>> >> >> >> +                                     | EXT_CSD_CARD_TYPE_52
>> >> >>  \
>> >> >> >> +                                     | EXT_CSD_CARD_TYPE_26)
>> >> >> >> +
>> >> >> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_2V_ALL
>> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V     \
>> >> >> >> +                                     | EXT_CSD_CARD_TYPE_52
>> >> >>  \
>> >> >> >> +                                     | EXT_CSD_CARD_TYPE_26)
>> >> >> >> +
>> >> >> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_8V_ALL
>> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V     \
>> >> >> >> +                                     | EXT_CSD_CARD_TYPE_52
>> >> >>  \
>> >> >> >> +                                     | EXT_CSD_CARD_TYPE_26)
>> >> >> >> +
>> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V
>> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
>> >> >> > \
>> >> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_52
>> >> >> > \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> +
>> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V
>> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
>> >> >> > \
>> >> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_52
>> >> >> > \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> +
>> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V
>> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
>> >> >> > \
>> >> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_52
>> >> >> > \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> +
>> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V
>> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
>> >> >> > \
>> >> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_52
>> >> >> > \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> +
>> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52
>> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_DDR_52
>> >> >> > \
>> >> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_52
>> >> >> > \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> +
>> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52
>> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_DDR_52
>> >> >> > \
>> >> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_52
>> >> >> > \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> +
>> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V
>> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
>> >> >> > \
>> >> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_52
>> >> >> > \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> +
>> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V
>> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
>> >> >> > \
>> >> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_52
>> >> >> > \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> +
>> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52
>> >> >> (EXT_CSD_CARD_TYPE_SDR_200
>> >> >> >> \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_DDR_52
>> >> >> > \
>> >> >> >> +                                             |
>> >> EXT_CSD_CARD_TYPE_52
>> >> >> > \
>> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >>
>> >> >> >>  #define EXT_CSD_BUS_WIDTH_1  0       /* Card is in 1 bit mode
>> */
>> >> >> >>  #define EXT_CSD_BUS_WIDTH_4  1       /* Card is in 4 bit mode
>> */
>> >> >> >> diff --git a/include/linux/mmc/sdhci.h
>> >> b/include/linux/mmc/sdhci.h
>> >> >> >> index e4b6935..d9a2222 100644
>> >> >> >> --- a/include/linux/mmc/sdhci.h
>> >> >> >> +++ b/include/linux/mmc/sdhci.h
>> >> >> >> @@ -121,6 +121,7 @@ struct sdhci_host {
>> >> >> >>  #define SDHCI_AUTO_CMD23     (1<<7)  /* Auto CMD23 support */
>> >> >> >>  #define SDHCI_PV_ENABLED     (1<<8)  /* Preset value enabled
>> */
>> >> >> >>  #define SDHCI_SDIO_IRQ_ENABLED       (1<<9)  /* SDIO irq
>> enabled
>> >> */
>> >> >> >> +#define SDHCI_HS200_NEEDS_TUNING (1<<10)     /* HS200 needs
>> >> tuning
>> >> >> */
>> >> >> >>
>> >> >> >>       unsigned int version;   /* SDHCI spec. version */
>> >> >> >>
>> >> >> >> --
>> >> >> >> 1.7.1
>> >> >> >>
>> >> >> >> --
>> >> >> >> To unsubscribe from this list: send the line "unsubscribe
>> linux-
>> >> mmc"
>> >> >> in
>> >> >> >> the body of a message to majordomo@vger.kernel.org
>> >> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
>> >> info.html
>> >> >> >
>> >> >> > --
>> >> >> > To unsubscribe from this list: send the line "unsubscribe
>> linux-
>> >> mmc"
>> >> >> in
>> >> >> > the body of a message to majordomo@vger.kernel.org
>> >> >> > More majordomo info at  http://vger.kernel.org/majordomo-
>> info.html
>> >> >> >
>> >> >> --
>> >> >> To unsubscribe from this list: send the line "unsubscribe linux-
>> mmc"
>> >> in
>> >> >> the body of a message to majordomo@vger.kernel.org
>> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
>> info.html
>> >> >
>> >> --
>> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc"
>> in
>> >> the body of a message to majordomo@vger.kernel.org
>> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> >
>
Subhash Jadavani Dec. 5, 2011, 11:29 a.m. UTC | #9
> -----Original Message-----
> From: Girish K S [mailto:girish.shivananjappa@linaro.org]
> Sent: Monday, December 05, 2011 12:20 PM
> To: Subhash Jadavani
> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
> soc@vger.kernel.org; Chris Ball
> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
> 
> On 5 December 2011 11:46, Subhash Jadavani <subhashj@codeaurora.org>
> wrote:
> >
> >
> >> -----Original Message-----
> >> From: Girish K S [mailto:girish.shivananjappa@linaro.org]
> >> Sent: Friday, December 02, 2011 5:08 PM
> >> To: Subhash Jadavani
> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
> >> soc@vger.kernel.org; Chris Ball
> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
> >>
> >> On 2 December 2011 00:02, Subhash Jadavani <subhashj@codeaurora.org>
> >> wrote:
> >> >
> >> >
> >> >> -----Original Message-----
> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
> >> >> Sent: Thursday, December 01, 2011 7:48 PM
> >> >> To: Subhash Jadavani
> >> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
> >> >> soc@vger.kernel.org; Chris Ball
> >> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC
> 4.5
> >> >>
> >> >> On 1 December 2011 16:27, Subhash Jadavani
> <subhashj@codeaurora.org>
> >> >> wrote:
> >> >> >
> >> >> >
> >> >> >> -----Original Message-----
> >> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
> >> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
> >> >> >> Sent: Thursday, December 01, 2011 3:58 PM
> >> >> >> To: Subhash Jadavani
> >> >> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-
> samsung-
> >> >> >> soc@vger.kernel.org; Chris Ball
> >> >> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC
> >> 4.5
> >> >> >>
> >> >> >> On 1 December 2011 15:33, Subhash Jadavani
> >> <subhashj@codeaurora.org>
> >> >> >> wrote:
> >> >> >> > Hi Girish,
> >> >> >> >
> >> >> >> >> -----Original Message-----
> >> >> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
> >> >> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
> >> >> >> >> Sent: Wednesday, November 30, 2011 2:24 PM
> >> >> >> >> To: linux-mmc@vger.kernel.org
> >> >> >> >> Cc: patches@linaro.org; linux-samsung-soc@vger.kernel.org;
> >> >> >> >> subhashj@codeaurora.org; Girish K S; Chris Ball
> >> >> >> >> Subject: [PATCH V5] mmc: core: HS200 mode support for eMMC
> 4.5
> >> >> >> >>
> >> >> >> >> This patch adds the support of the HS200 bus speed for eMMC
> >> 4.5
> >> >> >> >> devices.
> >> >> >> >> The eMMC 4.5 devices have support for 200MHz bus speed.The
> mmc
> >> >> core
> >> >> >> and
> >> >> >> >> host modules have been touched to add support for this
> module.
> >> >> >> >>
> >> >> >> >> It is necessary to know the card type in the sdhci.c file
> to
> >> add
> >> >> >> >> support
> >> >> >> >> for eMMC tuning function. So card.h file is included to
> import
> >> >> the
> >> >> >> card
> >> >> >> >> data structure.
> >> >> >> >>
> >> >> >> >> cc: Chris Ball <cjb@laptop.org>
> >> >> >> >> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
> >> >> >> >> ---
> >> >> >> >> Changes in v5:
> >> >> >> >>       Reduced the case statements for better code
> readability.
> >> >> >> Removed
> >> >> >> >>       unused macro definitions. Modified the tuning
> function
> >> >> >> prototype
> >> >> >> >>       and definition to support tuning for both SD and eMMC
> >> >> cards.
> >> >> >> >> Changes in v4:
> >> >> >> >>       Rebased onto chris-mmc/mmc-next branch. This patch is
> >> >> >> >> successfully
> >> >> >> >>       applied on commit with id
> >> >> >> >> de022ed3fdc14808299b2fa66dbb1ed5ab921912.
> >> >> >> >> Changes in v3:
> >> >> >> >>       In the previous commits of chris-mmc/mmc-next branch,
> >> the
> >> >> >> patch
> >> >> >> >> with
> >> >> >> >>       commit id (c0f22a2c92e357e7cb3988b0b13034d70b7461f9)
> >> >> defines
> >> >> >> >> caps2 for
> >> >> >> >>       more capabilities. This patch version deletes the
> member
> >> >> >> >> ext_caps(created
> >> >> >> >>       in my earlier patch) from struct mmc_host and reuses
> >> >> already
> >> >> >> >> accepted
> >> >> >> >>       caps2 member.
> >> >> >> >> Changes in v2:
> >> >> >> >>       Rebased to latest chris-mmc/mmc-next branch. Resolved
> >> >> >> indentation
> >> >> >> >>       problems identified in review. This patch has to be
> >> applied
> >> >> >> >> before
> >> >> >> >>       the patch released for modifying the printk messages.
> >> >> >> >> Changes in v1:
> >> >> >> >>       Case statements in switch that produce same result
> have
> >> >> >> >>       been combined to reduce repeated assignments.
> >> >> >> >>       patch recreated after rebase to chris balls mmc-next
> >> >> branch.
> >> >> >> >>
> >> >> >> >>  drivers/mmc/core/bus.c    |    3 +-
> >> >> >> >>  drivers/mmc/core/mmc.c    |   77
> >> >> >> >> ++++++++++++++++++++++++++++++++++++++++----
> >> >> >> >>  drivers/mmc/core/sd.c     |    3 +-
> >> >> >> >>  drivers/mmc/core/sdio.c   |    4 ++-
> >> >> >> >>  drivers/mmc/host/sdhci.c  |   38 +++++++++++++++++-----
> >> >> >> >>  include/linux/mmc/card.h  |    3 ++
> >> >> >> >>  include/linux/mmc/host.h  |   11 ++++++-
> >> >> >> >>  include/linux/mmc/mmc.h   |   66
> >> >> >> >> ++++++++++++++++++++++++++++++++++++++-
> >> >> >> >>  include/linux/mmc/sdhci.h |    1 +
> >> >> >> >>  9 files changed, 185 insertions(+), 21 deletions(-)
> >> >> >> >>
> >> >> >> >> diff --git a/drivers/mmc/core/bus.c
> b/drivers/mmc/core/bus.c
> >> >> >> >> index 5639fdf..83c9f8d 100644
> >> >> >> >> --- a/drivers/mmc/core/bus.c
> >> >> >> >> +++ b/drivers/mmc/core/bus.c
> >> >> >> >> @@ -301,10 +301,11 @@ int mmc_add_card(struct mmc_card
> *card)
> >> >> >> >>                       mmc_card_ddr_mode(card) ? "DDR " :
> "",
> >> >> >> >>                       type);
> >> >> >> >>       } else {
> >> >> >> >> -             printk(KERN_INFO "%s: new %s%s%s card at
> address
> >> >> >> %04x\n",
> >> >> >> >> +             pr_info("%s: new %s%s%s%s card at address
> >> %04x\n",
> >> >> >> >>                       mmc_hostname(card->host),
> >> >> >> >>                       mmc_card_uhs(card) ? "ultra high
> speed "
> >> :
> >> >> >> >>                       (mmc_card_highspeed(card) ? "high
> speed
> >> " :
> >> >> >> ""),
> >> >> >> >> +                     (mmc_card_hs200(card) ? "HS200 " :
> ""),
> >> >> >> >>                       mmc_card_ddr_mode(card) ? "DDR " :
> "",
> >> >> >> >>                       type, card->rca);
> >> >> >> >>       }
> >> >> >> >> diff --git a/drivers/mmc/core/mmc.c
> b/drivers/mmc/core/mmc.c
> >> >> >> >> index a1223bd..f4124d6 100644
> >> >> >> >> --- a/drivers/mmc/core/mmc.c
> >> >> >> >> +++ b/drivers/mmc/core/mmc.c
> >> >> >> >> @@ -285,6 +285,27 @@ static int mmc_read_ext_csd(struct
> >> mmc_card
> >> >> >> *card,
> >> >> >> >> u8 *ext_csd)
> >> >> >> >>       }
> >> >> >> >>       card->ext_csd.raw_card_type =
> >> ext_csd[EXT_CSD_CARD_TYPE];
> >> >> >> >>       switch (ext_csd[EXT_CSD_CARD_TYPE] &
> >> >> EXT_CSD_CARD_TYPE_MASK) {
> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL:
> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
> >> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
> >> >> >> >> +             card->ext_csd.card_type =
> >> >> EXT_CSD_CARD_TYPE_SDR_200;
> >> >> >> >> +             break;
> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
> >> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
> >> >> >> >> +             card->ext_csd.card_type =
> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V;
> >> >> >> >> +             break;
> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
> >> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
> >> >> >> >> +             card->ext_csd.card_type =
> >> >> EXT_CSD_CARD_TYPE_SDR_1_8V;
> >> >> >> >> +             break;
> >> >> >> >>       case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52
> |
> >> >> >> >>            EXT_CSD_CARD_TYPE_26:
> >> >> >> >>               card->ext_csd.hs_max_dtr = 52000000;
> >> >> >> >> @@ -699,6 +720,7 @@ static int mmc_init_card(struct
> mmc_host
> >> >> *host,
> >> >> >> u32
> >> >> >> >> ocr,
> >> >> >> >>  {
> >> >> >> >>       struct mmc_card *card;
> >> >> >> >>       int err, ddr = 0;
> >> >> >> >> +     int hs_sdr = 0;
> >> >> >> >>       u32 cid[4];
> >> >> >> >>       unsigned int max_dtr;
> >> >> >> >>       u32 rocr;
> >> >> >> >> @@ -894,11 +916,16 @@ static int mmc_init_card(struct
> mmc_host
> >> >> >> *host,
> >> >> >> >> u32 ocr,
> >> >> >> >>       /*
> >> >> >> >>        * Activate high speed (if supported)
> >> >> >> >>        */
> >> >> >> >> -     if ((card->ext_csd.hs_max_dtr != 0) &&
> >> >> >> >> -             (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
> >> >> >> >> -             err = mmc_switch(card,
> EXT_CSD_CMD_SET_NORMAL,
> >> >> >> >> -                              EXT_CSD_HS_TIMING, 1,
> >> >> >> >> -                              card-
> >> >ext_csd.generic_cmd6_time);
> >> >> >> >> +     if (card->ext_csd.hs_max_dtr != 0) {
> >> >> >> >> +             err = 0;
> >> >> >> >> +             if ((card->ext_csd.hs_max_dtr > 52000000) &&
> >> >> >> >> +                 (host->caps2 & MMC_CAP2_HS200))
> >> >> >> >> +                     err = mmc_switch(card,
> >> >> EXT_CSD_CMD_SET_NORMAL,
> >> >> >> >> +                                      EXT_CSD_HS_TIMING,
> 2,
> >> 0);
> >> >> >> >> +             else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
> >> >> >> >> +                     err = mmc_switch(card,
> >> >> EXT_CSD_CMD_SET_NORMAL,
> >> >> >> >> +                                      EXT_CSD_HS_TIMING,
> 1,
> >> 0);
> >> >> >> >> +
> >> >> >> >>               if (err && err != -EBADMSG)
> >> >> >> >>                       goto free_card;
> >> >> >> >>
> >> >> >> >> @@ -907,7 +934,11 @@ static int mmc_init_card(struct
> mmc_host
> >> >> *host,
> >> >> >> >> u32 ocr,
> >> >> >> >>                              mmc_hostname(card->host));
> >> >> >> >>                       err = 0;
> >> >> >> >>               } else {
> >> >> >> >> -                     mmc_card_set_highspeed(card);
> >> >> >> >> +                     if ((card->ext_csd.hs_max_dtr >
> >> 52000000)
> >> >> &&
> >> >> >> >> +                         (host->caps2 & MMC_CAP2_HS200))
> >> >> >> >> +                             mmc_card_set_hs200(card);
> >> >> >> >> +                     else
> >> >> >> >> +                             mmc_card_set_highspeed(card);
> >> >> >> >>                       mmc_set_timing(card->host,
> >> >> MMC_TIMING_MMC_HS);
> >> >> >> >
> >> >> >> > MMC_TIMING_MMC_HS200 is defined but still not used.
> >> >> >> >
> >> >> >> > So I guess it should be like this ::
> >> >> >> >  +                      if ((card->ext_csd.hs_max_dtr >
> >> 52000000)
> >> >> &&
> >> >> >> >  +                          (host->caps2 & MMC_CAP2_HS200))
> {
> >> >> >> >  +                              mmc_card_set_hs200(card);
> >> >> >> >  +                      mmc_set_timing(card->host,
> >> >> >> MMC_TIMING_MMC_HS200)
> >> >> >> >  +                      } else {
> >> >> >> >  +
>  mmc_card_set_highspeed(card);
> >> >> >> >  +                              mmc_set_timing(card->host,
> >> >> >> > MMC_TIMING_MMC_HS)
> >> >> >> >  +                      }
> >> >> >> >
> >> >> >> >
> >> >> >> >
> >> >> >> >
> >> >> >> >
> >> >> >> >
> >> >> >> >
> >> >> >> >
> >> >> >> >
> >> >> >> >
> >> >> >> >
> >> >> >> >
> >> >> >> >
> >> >> >> >
> >> >> >> >>               }
> >> >> >> >>       }
> >> >> >> >> @@ -933,7 +964,7 @@ static int mmc_init_card(struct
> mmc_host
> >> >> *host,
> >> >> >> u32
> >> >> >> >> ocr,
> >> >> >> >>        */
> >> >> >> >>       max_dtr = (unsigned int)-1;
> >> >> >> >>
> >> >> >> >> -     if (mmc_card_highspeed(card)) {
> >> >> >> >> +     if (mmc_card_highspeed(card) || mmc_card_hs200(card))
> {
> >> >> >> >>               if (max_dtr > card->ext_csd.hs_max_dtr)
> >> >> >> >>                       max_dtr = card->ext_csd.hs_max_dtr;
> >> >> >> >>       } else if (max_dtr > card->csd.max_dtr) {
> >> >> >> >> @@ -959,6 +990,18 @@ static int mmc_init_card(struct
> mmc_host
> >> >> *host,
> >> >> >> >> u32 ocr,
> >> >> >> >>       }
> >> >> >> >>
> >> >> >> >>       /*
> >> >> >> >> +      * Indicate HS200 SDR mode (if supported).
> >> >> >> >> +      */
> >> >> >> >> +     if (mmc_card_hs200(card)) {
> >> >> >> >> +             if ((card->ext_csd.card_type &
> >> >> >> EXT_CSD_CARD_TYPE_SDR_1_8V)
> >> >> >> >> +                     && (host->caps2 &
> >> MMC_CAP2_HS200_1_8V_SDR))
> >> >> >> >> +                             hs_sdr = MMC_1_8V_SDR_MODE;
> >> >> >> >> +             else if ((card->ext_csd.card_type &
> >> >> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
> >> >> >> >> +                     && (host->caps2 &
> >> MMC_CAP2_HS200_1_2V_SDR))
> >> >> >> >> +                             hs_sdr = MMC_1_2V_SDR_MODE;
> >> >> >> >> +     }
> >> >> >> >> +
> >> >> >> >> +     /*
> >> >> >> >>        * Activate wide bus and DDR (if supported).
> >> >> >> >>        */
> >> >> >> >>       if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
> >> >> >> >> @@ -998,6 +1041,17 @@ static int mmc_init_card(struct
> mmc_host
> >> >> >> *host,
> >> >> >> >> u32 ocr,
> >> >> >> >>                       if (!err) {
> >> >> >> >>                               mmc_set_bus_width(card->host,
> >> >> >> bus_width);
> >> >> >> >>
> >> >> >> >> +                             if ((host->caps2 &
> >> MMC_CAP2_HS200)
> >> >> &&
> >> >> >> >> +                                 card->host->ops-
> >> >> >execute_tuning)
> >> >> >> >> +                                     err = card->host-
> >ops->
> >> \
> >> >> >> >> +
> >> execute_tuning(card-
> >> >> >> >host,
> >> >> >> >> +
> >> >> >> > MMC_SEND_TUNING_BLOCK_HS200);
> >> >> >> >
> >> >> >> >
> >> >> >> > execute_tuning should be done right after the timing is
> changed
> >> to
> >> >> >> HS200 and
> >> >> >> > clock rate is changed to 200Mhz. This is not the correct
> >> sequence
> >> >> to
> >> >> >> call
> >> >> >> > the execute_tuning().
> >> >> >> > As told earlier, It is mentioned in the spec that tuning
> should
> >> be
> >> >> >> executed after change of buswidth (mandatory). Also it
> mentions
> >> that
> >> >> >> "The host may invoke the HS200 tuning sequence, by sending
> CMD21
> >> to
> >> >> the
> >> >> >> device". It means that
> >> >> >>  after setting the HS200 mode, Changing to freq > 52Mhz and
> >> changing
> >> >> >> the bus width tuning can be executed anytime to identify the
> >> >> sampling
> >> >> >> point to read.(By anytime i mean before actual block read
> >> >> Operation).
> >> >> >> Can you please point me to the place in the spec where it
> >> specifies
> >> >> >> tuning should be done immediately after freq change (may be i
> >> missed
> >> >> >> to read it).
> >> >> >
> >> >> >
> >> >> > Ok. let me ask you this. Why do we run the execute_tuning()?
> It's
> >> to
> >> >> tune
> >> >> > the sampling clock generator of host controller before you
> start
> >> any
> >> >> read
> >> >> > operation (on command line or data line) from card. If you
> don't
> >> tune
> >> >> the
> >> >> > sampling clock generator before the read operation (after
> changing
> >> >> the
> >> >> > timing to HS200 and clock rate to 200mhz), you can't be sure
> that
> >> >> read
> >> >> > operation from card will be completed without errors. You may
> get
> >> the
> >> >> data /
> >> >> > cmd response CRC errors. At least this will surely fail on our
> MSM
> >> >> SDCC host
> >> >> > controller. That's what we had faced with SD3.0 UHS-I tuning as
> >> well
> >> >> as
> >> >> > mentioned in http://www.spinics.net/lists/linux-arm-
> >> >> msm/msg03867.html.
> >> >
> >> >> > this tuning is done before any read opration for the best bus
> >> width
> >> >> supported.
> >> > Agreed. But can we be sure that "command response" for bus width
> >> change via
> >> > CMD6, will not have any command CRC failures if tuning is not
> done?
> >> All responses are sent on CMD line not on data lines, And sampling
> is
> >> done for Data lines before reading. So command CRC failure doesnt
> >> depend on tuning. If you get error during CMD6 it could be that
> device
> >> cannot support the bus width at the set frequency.
> >
> > I guess it's not the correct assumption here. Sampling point tuning
> is to
> Its Not assumption "Specification says responses are all sent on CMD
> only"



Where does it say that tuning is not required for data received on command
line? If the 200Mhz clock can effect the data received on DATA lines then
why it won't affect the data (responses) received on CMD lines?
If you still have doubt, I would suggest to get the clarification from
JEDEC.  From SD3.01 spec, for sure CMD lines also requires tuning.

"Sampling clock generation" on our host controller also says that tuning is
required for data transfer on both DATA and CMD lines.

I am not sure what is the issue with doing the tuning immediately after
changing to bus speed mode to HS200 (changing controller timing, changing
clock etc ...)? This is what we are doing it for SD3.0 cards as well.

Your current implementation is not going to work with all host controllers.






> > tune the sampling point for data received on both CMD and DATA lines
> (not
> > just data lines). I can't find detailed mentioning of this in eMMC4.5
> Pls check the section 6.6.7.1. the 2nd paragraph quotes "which in turn
> uses it to find the
> optimal sampling point for the data lines"
> > (that's the documentation short coming, you can even confirm whether
> tuning
> > procedure is required for CMD line or not from JEDEC) but SD3.01
> > specification does mention this tuning procedure in great details.
> NOTE:
> > eMMC4.5 HS200 mode is mostly inspired from SD3.01 UHS-I bus speed
> modes.
> >
> > Section " 4.2.4.5 Tuning Command" in "SD3.01 - Simplified
> >
> (Part_1_Physical_Layer_Simplified_Specification_Ver_3.01_Final_100518)"
> > specification(can be downloaded from here:
> > https://www.sdcard.org/downloads/pls/), clearly states this:
> >
> > 4.2.4.5 Tuning Command
> > CMD19 is defined for Send Tuning Block Command. R1 type response is
> defined.
> > CMD19 can be
> > executed in transfer state of 1.8V signaling mode while the card is
> > unlocked. The other case, CMD19 is
> > treated as illegal command. Data block, carried by DAT[3:0], contains
> a
> > pattern for tuning sampling
> > position to receive data on the CMD and DAT[3:0] line. The block
> length of
> > CMD19 is fixed and CMD16
> > is not required.
> > I have no idea of the SD spec. I have just seen the eMMC spec and
> above quotes might answer your doubt
> > So before tuning, you may get the Command CRC errors in HS200 mode.
> >
> > Regards,
> > Subhash
> >
> >> >
> >> >> ps:Chris need your comment on this
> >> >> >
> >> >> >> >> +
> >> >> >> >> +                             if (err) {
> >> >> >> >> +                                     pr_warning("tuning
> >> >> execution
> >> >> >> > failed\n");
> >> >> >> >> +                                     continue;
> >> >> >> >> +                             }
> >> >> >> >> +
> >> >> >> >>                               /*
> >> >> >> >>                                * If controller can't handle
> >> bus
> >> >> >> width
> >> >> >> > test,
> >> >> >> >>                                * compare ext_csd previously
> >> read
> >> >> in
> >> >> >> 1 bit
> >> >> >> >> mode
> >> >> >> >> @@ -1056,6 +1110,15 @@ static int mmc_init_card(struct
> >> mmc_host
> >> >> >> *host,
> >> >> >> >> u32 ocr,
> >> >> >> >>                       mmc_card_set_ddr_mode(card);
> >> >> >> >>                       mmc_set_timing(card->host,
> >> >> >> MMC_TIMING_UHS_DDR50);
> >> >> >> >>                       mmc_set_bus_width(card->host,
> >> bus_width);
> >> >> >> >> +             } else if (hs_sdr) {
> >> >> >> >> +                     if (hs_sdr ==
> >> EXT_CSD_CARD_TYPE_SDR_1_2V) {
> >> >> >> >> +                             err =
> >> mmc_set_signal_voltage(host,
> >> >> >> >> +
> MMC_SIGNAL_VOLTAGE_120,
> >> 0);
> >> >> >> >> +                             if (err)
> >> >> >> >> +                                     goto err;
> >> >> >> >> +                     }
> >> >> >> >> +                     mmc_set_timing(card->host,
> >> >> MMC_TIMING_MMC_HS);
> >> >> >> >> +                     mmc_set_bus_width(card->host,
> >> bus_width);
> >> >> >> >>               }
> >> >> >> >>       }
> >> >> >> >>
> >> >> >> >> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> >> >> >> >> index 1d5a3bd..c1d3ee3 100644
> >> >> >> >> --- a/drivers/mmc/core/sd.c
> >> >> >> >> +++ b/drivers/mmc/core/sd.c
> >> >> >> >> @@ -660,7 +660,8 @@ static int mmc_sd_init_uhs_card(struct
> >> >> mmc_card
> >> >> >> >> *card)
> >> >> >> >>
> >> >> >> >>       /* SPI mode doesn't define CMD19 */
> >> >> >> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
> >> >> >> >> >execute_tuning)
> >> >> >> >> -             err = card->host->ops->execute_tuning(card-
> >> >host);
> >> >> >> >> +             err = card->host->ops->execute_tuning(card-
> >> >host,
> >> >> >>   \
> >> >> >> >> +
> >> >> >> > MMC_SEND_TUNING_BLOCK);
> >> >> >> >>
> >> >> >> >>  out:
> >> >> >> >>       kfree(status);
> >> >> >> >> diff --git a/drivers/mmc/core/sdio.c
> b/drivers/mmc/core/sdio.c
> >> >> >> >> index 8c04f7f..8ef8817 100644
> >> >> >> >> --- a/drivers/mmc/core/sdio.c
> >> >> >> >> +++ b/drivers/mmc/core/sdio.c
> >> >> >> >> @@ -14,6 +14,7 @@
> >> >> >> >>
> >> >> >> >>  #include <linux/mmc/host.h>
> >> >> >> >>  #include <linux/mmc/card.h>
> >> >> >> >> +#include <linux/mmc/mmc.h>
> >> >> >> >>  #include <linux/mmc/sdio.h>
> >> >> >> >>  #include <linux/mmc/sdio_func.h>
> >> >> >> >>  #include <linux/mmc/sdio_ids.h>
> >> >> >> >> @@ -556,7 +557,8 @@ static int
> mmc_sdio_init_uhs_card(struct
> >> >> >> mmc_card
> >> >> >> >> *card)
> >> >> >> >>
> >> >> >> >>       /* Initialize and start re-tuning timer */
> >> >> >> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
> >> >> >> >> >execute_tuning)
> >> >> >> >> -             err = card->host->ops->execute_tuning(card-
> >> >host);
> >> >> >> >> +             err = card->host->ops->execute_tuning(card-
> >> >host,
> >> >> >> >> +
> >> >> >> > MMC_SEND_TUNING_BLOCK);
> >> >> >> >>
> >> >> >> >>  out:
> >> >> >> >>
> >> >> >> >> diff --git a/drivers/mmc/host/sdhci.c
> >> b/drivers/mmc/host/sdhci.c
> >> >> >> >> index a7c2311..13d74bb 100644
> >> >> >> >> --- a/drivers/mmc/host/sdhci.c
> >> >> >> >> +++ b/drivers/mmc/host/sdhci.c
> >> >> >> >> @@ -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
> >> >> >> >> @@ -1016,7 +1016,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
> >> >> */
> >> >> >> >> @@ -1673,7 +1674,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;
> >> >> >> >> @@ -1694,10 +1695,13 @@ static int
> sdhci_execute_tuning(struct
> >> >> >> mmc_host
> >> >> >> >> *mmc)
> >> >> >> >>        * Host Controller needs tuning only in case of
> SDR104
> >> mode
> >> >> >> >>        * and for SDR50 mode when Use Tuning for SDR50 is
> set
> >> in
> >> >> >> >>        * Capabilities register.
> >> >> >> >> +      * If the Host Controller supports the HS200 mode
> then
> >> >> tuning
> >> >> >> >> +      * function has to be executed.
> >> >> >> >>        */
> >> >> >> >>       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)))
> >> >> >> >> +         (host->flags & SDHCI_SDR50_NEEDS_TUNING)) ||
> >> >> >> >> +         (host->flags & SDHCI_HS200_NEEDS_TUNING))
> >> >> >> >>               ctrl |= SDHCI_CTRL_EXEC_TUNING;
> >> >> >> >>       else {
> >> >> >> >>               spin_unlock(&host->lock);
> >> >> >> >> @@ -1733,7 +1737,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;
> >> >> >> >> @@ -1748,7 +1752,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.
> >> >> >> >> @@ -2131,12 +2145,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;
> >> >> >> >> @@ -2741,6 +2757,10 @@ int sdhci_add_host(struct sdhci_host
> >> >> *host)
> >> >> >> >>       if (caps[1] & SDHCI_USE_SDR50_TUNING)
> >> >> >> >>               host->flags |= SDHCI_SDR50_NEEDS_TUNING;
> >> >> >> >>
> >> >> >> >> +     /* Does the host needs 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;
> >> >> >> >> diff --git a/include/linux/mmc/card.h
> >> b/include/linux/mmc/card.h
> >> >> >> >> index 534974c..e76f649 100644
> >> >> >> >> --- a/include/linux/mmc/card.h
> >> >> >> >> +++ b/include/linux/mmc/card.h
> >> >> >> >> @@ -209,6 +209,7 @@ struct mmc_card {
> >> >> >> >>  #define MMC_STATE_HIGHSPEED_DDR (1<<4)               /*
> card
> >> is
> >> >> in
> >> >> >> high
> >> >> >> >> speed mode */
> >> >> >> >>  #define MMC_STATE_ULTRAHIGHSPEED (1<<5)              /*
> card
> >> is
> >> >> in
> >> >> >> ultra
> >> >> >> >> high speed mode */
> >> >> >> >>  #define MMC_CARD_SDXC                (1<<6)          /*
> card
> >> is
> >> >> >> SDXC */
> >> >> >> >> +#define MMC_STATE_HIGHSPEED_200      (1<<7)  /* card is in
> >> HS200
> >> >> >> >> mode */
> >> >> >> >>       unsigned int            quirks;         /* card
> quirks
> >> */
> >> >> >> >>  #define MMC_QUIRK_LENIENT_FN0        (1<<0)          /*
> allow
> >> >> SDIO
> >> >> >> FN0
> >> >> >> >> writes outside of the VS CCCR range */
> >> >> >> >>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func-
> >> >> >> >> >cur_blksize */
> >> >> >> >> @@ -365,6 +366,7 @@ static inline void __maybe_unused
> >> >> >> >> remove_quirk(struct mmc_card *card, int data)
> >> >> >> >>  #define mmc_card_present(c)  ((c)->state &
> MMC_STATE_PRESENT)
> >> >> >> >>  #define mmc_card_readonly(c) ((c)->state &
> >> MMC_STATE_READONLY)
> >> >> >> >>  #define mmc_card_highspeed(c)        ((c)->state &
> >> >> >> MMC_STATE_HIGHSPEED)
> >> >> >> >> +#define mmc_card_hs200(c)    ((c)->state &
> >> >> MMC_STATE_HIGHSPEED_200)
> >> >> >> >>  #define mmc_card_blockaddr(c)        ((c)->state &
> >> >> >> MMC_STATE_BLOCKADDR)
> >> >> >> >>  #define mmc_card_ddr_mode(c) ((c)->state &
> >> >> MMC_STATE_HIGHSPEED_DDR)
> >> >> >> >>  #define mmc_card_uhs(c)              ((c)->state &
> >> >> >> >> MMC_STATE_ULTRAHIGHSPEED)
> >> >> >> >> @@ -374,6 +376,7 @@ static inline void __maybe_unused
> >> >> >> >> remove_quirk(struct mmc_card *card, int data)
> >> >> >> >>  #define mmc_card_set_present(c)      ((c)->state |=
> >> >> >> MMC_STATE_PRESENT)
> >> >> >> >>  #define mmc_card_set_readonly(c) ((c)->state |=
> >> >> MMC_STATE_READONLY)
> >> >> >> >>  #define mmc_card_set_highspeed(c) ((c)->state |=
> >> >> >> MMC_STATE_HIGHSPEED)
> >> >> >> >> +#define mmc_card_set_hs200(c)        ((c)->state |=
> >> >> >> >> MMC_STATE_HIGHSPEED_200)
> >> >> >> >>  #define mmc_card_set_blockaddr(c) ((c)->state |=
> >> >> >> MMC_STATE_BLOCKADDR)
> >> >> >> >>  #define mmc_card_set_ddr_mode(c) ((c)->state |=
> >> >> >> >> MMC_STATE_HIGHSPEED_DDR)
> >> >> >> >>  #define mmc_card_set_uhs(c) ((c)->state |=
> >> >> >> MMC_STATE_ULTRAHIGHSPEED)
> >> >> >> >> diff --git a/include/linux/mmc/host.h
> >> b/include/linux/mmc/host.h
> >> >> >> >> index 706f722..5eac57a 100644
> >> >> >> >> --- a/include/linux/mmc/host.h
> >> >> >> >> +++ b/include/linux/mmc/host.h
> >> >> >> >> @@ -50,6 +50,7 @@ struct mmc_ios {
> >> >> >> >>
> >> >> >> >>  #define MMC_TIMING_LEGACY    0
> >> >> >> >>  #define MMC_TIMING_MMC_HS    1
> >> >> >> >> +#define MMC_TIMING_MMC_HS200 2
> >> >> >> >>  #define MMC_TIMING_SD_HS     2
> >> >> >> >>  #define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY
> >> >> >> >>  #define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS
> >> >> >> >> @@ -60,6 +61,8 @@ struct mmc_ios {
> >> >> >> >>  #define MMC_SDR_MODE         0
> >> >> >> >>  #define MMC_1_2V_DDR_MODE    1
> >> >> >> >>  #define MMC_1_8V_DDR_MODE    2
> >> >> >> >> +#define MMC_1_2V_SDR_MODE    3
> >> >> >> >> +#define MMC_1_8V_SDR_MODE    4
> >> >> >> >>
> >> >> >> >>       unsigned char   signal_voltage;         /* signalling
> >> >> voltage
> >> >> >> >> (1.8V or 3.3V) */
> >> >> >> >>
> >> >> >> >> @@ -148,7 +151,9 @@ struct mmc_host_ops {
> >> >> >> >>       void    (*init_card)(struct mmc_host *host, struct
> >> mmc_card
> >> >> >> *card);
> >> >> >> >>
> >> >> >> >>       int     (*start_signal_voltage_switch)(struct
> mmc_host
> >> >> *host,
> >> >> >> >> struct mmc_ios *ios);
> >> >> >> >> -     int     (*execute_tuning)(struct mmc_host *host);
> >> >> >> >> +
> >> >> >> >> +     /* The tuning command opcode value is different for
> SD
> >> and
> >> >> >> eMMC
> >> >> >> >> cards */
> >> >> >> >> +     int     (*execute_tuning)(struct mmc_host *host, u32
> >> >> opcode);
> >> >> >> >>       void    (*enable_preset_value)(struct mmc_host *host,
> >> bool
> >> >> >> enable);
> >> >> >> >>       int     (*select_drive_strength)(unsigned int
> max_dtr,
> >> int
> >> >> >> >> host_drv, int card_drv);
> >> >> >> >>       void    (*hw_reset)(struct mmc_host *host);
> >> >> >> >> @@ -242,6 +247,10 @@ struct mmc_host {
> >> >> >> >>  #define MMC_CAP2_CACHE_CTRL  (1 << 1)        /* Allow
> cache
> >> >> control
> >> >> >> */
> >> >> >> >>  #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)    /* Notify
> >> poweroff
> >> >> >> >> supported */
> >> >> >> >>  #define MMC_CAP2_NO_MULTI_READ       (1 << 3)        /*
> >> >> Multiblock
> >> >> >> reads
> >> >> >> >> don't work */
> >> >> >> >> +#define MMC_CAP2_HS200_1_8V_SDR      (1 << 4)        /*
> can
> >> >> support
> >> >> >> */
> >> >> >> >> +#define MMC_CAP2_HS200_1_2V_SDR      (1 << 5)        /*
> can
> >> >> support
> >> >> >> */
> >> >> >> >> +#define MMC_CAP2_HS200
> (MMC_CAP2_HS200_1_8V_SDR
> >> |
> >> >> \
> >> >> >> >> +                              MMC_CAP2_HS200_1_2V_SDR)
> >> >> >> >>
> >> >> >> >>       mmc_pm_flag_t           pm_caps;        /* supported
> pm
> >> >> >> features */
> >> >> >> >>       unsigned int        power_notify_type;
> >> >> >> >> diff --git a/include/linux/mmc/mmc.h
> b/include/linux/mmc/mmc.h
> >> >> >> >> index 0e71356..7996272 100644
> >> >> >> >> --- a/include/linux/mmc/mmc.h
> >> >> >> >> +++ b/include/linux/mmc/mmc.h
> >> >> >> >> @@ -51,6 +51,7 @@
> >> >> >> >>  #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data
> >> addr
> >> >> R1
> >> >> >> >> */
> >> >> >> >>  #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data
> >> addr
> >> >> R1
> >> >> >> >> */
> >> >> >> >>  #define MMC_SEND_TUNING_BLOCK    19   /* adtc
> >> >>  R1
> >> >> >> >> */
> >> >> >> >> +#define MMC_SEND_TUNING_BLOCK_HS200  21      /* adtc R1
>  */
> >> >> >> >>
> >> >> >> >>    /* class 3 */
> >> >> >> >>  #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data
> >> addr
> >> >> R1
> >> >> >> >> */
> >> >> >> >> @@ -333,13 +334,76 @@ struct _mmc_csd {
> >> >> >> >>
> >> >> >> >>  #define EXT_CSD_CARD_TYPE_26 (1<<0)  /* Card can run at
> 26MHz
> >> */
> >> >> >> >>  #define EXT_CSD_CARD_TYPE_52 (1<<1)  /* Card can run at
> 52MHz
> >> */
> >> >> >> >> -#define EXT_CSD_CARD_TYPE_MASK       0xF     /* Mask out
> >> >> reserved
> >> >> >> bits */
> >> >> >> >> +#define EXT_CSD_CARD_TYPE_MASK       0x3F    /* Mask out
> >> >> reserved
> >> >> >> bits */
> >> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can
> run
> >> at
> >> >> >> 52MHz
> >> >> >> >> */
> >> >> >> >>                                            /* DDR mode
> @1.8V
> >> or
> >> >> 3V
> >> >> >> I/O */
> >> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can
> run
> >> at
> >> >> >> 52MHz
> >> >> >> >> */
> >> >> >> >>                                            /* DDR mode
> @1.2V
> >> I/O
> >> >> */
> >> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_52
> >> >> (EXT_CSD_CARD_TYPE_DDR_1_8V
> >> >> >>  \
> >> >> >> >>                                       |
> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V)
> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V   (1<<4)  /* Card can
> run
> >> at
> >> >> >> >> 200MHz */
> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V   (1<<5)  /* Card can
> run
> >> at
> >> >> >> >> 200MHz */
> >> >> >> >> +                                             /* SDR mode
> >> @1.2V
> >> >> I/O
> >> >> >> */
> >> >> >> >> +
> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_200
> >>  (EXT_CSD_CARD_TYPE_SDR_1_8V
> >> >> >>   \
> >> >> >> >> +                                     |
> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
> >> >> >> >> +
> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL
> >>  (EXT_CSD_CARD_TYPE_SDR_200
> >> >> >>  \
> >> >> >> >> +                                     |
> EXT_CSD_CARD_TYPE_52
> >> >> >>  \
> >> >> >> >> +                                     |
> EXT_CSD_CARD_TYPE_26)
> >> >> >> >> +
> >> >> >> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_2V_ALL
> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V     \
> >> >> >> >> +                                     |
> EXT_CSD_CARD_TYPE_52
> >> >> >>  \
> >> >> >> >> +                                     |
> EXT_CSD_CARD_TYPE_26)
> >> >> >> >> +
> >> >> >> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_8V_ALL
> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V     \
> >> >> >> >> +                                     |
> EXT_CSD_CARD_TYPE_52
> >> >> >>  \
> >> >> >> >> +                                     |
> EXT_CSD_CARD_TYPE_26)
> >> >> >> >> +
> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V
> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_52
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> >> +
> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V
> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_52
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> >> +
> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V
> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_52
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> >> +
> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V
> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_52
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> >> +
> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52
> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_DDR_52
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_52
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> >> +
> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52
> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_DDR_52
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_52
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> >> +
> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V
> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_52
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> >> +
> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V
> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_52
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> >> +
> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52
> >> >> >> (EXT_CSD_CARD_TYPE_SDR_200
> >> >> >> >> \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_DDR_52
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> EXT_CSD_CARD_TYPE_52
> >> >> >> > \
> >> >> >> >> +                                             |
> >> >> >> EXT_CSD_CARD_TYPE_26)
> >> >> >> >>
> >> >> >> >>  #define EXT_CSD_BUS_WIDTH_1  0       /* Card is in 1 bit
> mode
> >> */
> >> >> >> >>  #define EXT_CSD_BUS_WIDTH_4  1       /* Card is in 4 bit
> mode
> >> */
> >> >> >> >> diff --git a/include/linux/mmc/sdhci.h
> >> >> b/include/linux/mmc/sdhci.h
> >> >> >> >> index e4b6935..d9a2222 100644
> >> >> >> >> --- a/include/linux/mmc/sdhci.h
> >> >> >> >> +++ b/include/linux/mmc/sdhci.h
> >> >> >> >> @@ -121,6 +121,7 @@ struct sdhci_host {
> >> >> >> >>  #define SDHCI_AUTO_CMD23     (1<<7)  /* Auto CMD23 support
> */
> >> >> >> >>  #define SDHCI_PV_ENABLED     (1<<8)  /* Preset value
> enabled
> >> */
> >> >> >> >>  #define SDHCI_SDIO_IRQ_ENABLED       (1<<9)  /* SDIO irq
> >> enabled
> >> >> */
> >> >> >> >> +#define SDHCI_HS200_NEEDS_TUNING (1<<10)     /* HS200
> needs
> >> >> tuning
> >> >> >> */
> >> >> >> >>
> >> >> >> >>       unsigned int version;   /* SDHCI spec. version */
> >> >> >> >>
> >> >> >> >> --
> >> >> >> >> 1.7.1
> >> >> >> >>
> >> >> >> >> --
> >> >> >> >> To unsubscribe from this list: send the line "unsubscribe
> >> linux-
> >> >> mmc"
> >> >> >> in
> >> >> >> >> the body of a message to majordomo@vger.kernel.org
> >> >> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
> >> >> info.html
> >> >> >> >
> >> >> >> > --
> >> >> >> > To unsubscribe from this list: send the line "unsubscribe
> >> linux-
> >> >> mmc"
> >> >> >> in
> >> >> >> > the body of a message to majordomo@vger.kernel.org
> >> >> >> > More majordomo info at  http://vger.kernel.org/majordomo-
> >> info.html
> >> >> >> >
> >> >> >> --
> >> >> >> To unsubscribe from this list: send the line "unsubscribe
> linux-
> >> mmc"
> >> >> in
> >> >> >> the body of a message to majordomo@vger.kernel.org
> >> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
> >> info.html
> >> >> >
> >> >> --
> >> >> To unsubscribe from this list: send the line "unsubscribe linux-
> mmc"
> >> in
> >> >> the body of a message to majordomo@vger.kernel.org
> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
> info.html
> >> >
> >
Saugata Das Dec. 5, 2011, 2:59 p.m. UTC | #10
Hi Girish

Please refer to Figure 71 (HS200 device output timing) of the MMC-4.5
spec. It shows that both CMD and DATA[7-0] will have some latency till
valid window. This implies that even the CMD line will need tuning for
reading the response. The specification talks about identifying
sampling point for data lines by reading tuning blocks. Based on host
controller capability, even the CMD line will get the good sample
point during the same tuning sequence.

We need to have the tuning done (execute_tuning) soon after switching
to HS200 mode and 200MHz clock.


Regards
Saugata


On 5 December 2011 16:59, Subhash Jadavani <subhashj@codeaurora.org> wrote:
>
>
>> -----Original Message-----
>> From: Girish K S [mailto:girish.shivananjappa@linaro.org]
>> Sent: Monday, December 05, 2011 12:20 PM
>> To: Subhash Jadavani
>> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>> soc@vger.kernel.org; Chris Ball
>> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>>
>> On 5 December 2011 11:46, Subhash Jadavani <subhashj@codeaurora.org>
>> wrote:
>> >
>> >
>> >> -----Original Message-----
>> >> From: Girish K S [mailto:girish.shivananjappa@linaro.org]
>> >> Sent: Friday, December 02, 2011 5:08 PM
>> >> To: Subhash Jadavani
>> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>> >> soc@vger.kernel.org; Chris Ball
>> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>> >>
>> >> On 2 December 2011 00:02, Subhash Jadavani <subhashj@codeaurora.org>
>> >> wrote:
>> >> >
>> >> >
>> >> >> -----Original Message-----
>> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
>> >> >> Sent: Thursday, December 01, 2011 7:48 PM
>> >> >> To: Subhash Jadavani
>> >> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>> >> >> soc@vger.kernel.org; Chris Ball
>> >> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC
>> 4.5
>> >> >>
>> >> >> On 1 December 2011 16:27, Subhash Jadavani
>> <subhashj@codeaurora.org>
>> >> >> wrote:
>> >> >> >
>> >> >> >
>> >> >> >> -----Original Message-----
>> >> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>> >> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
>> >> >> >> Sent: Thursday, December 01, 2011 3:58 PM
>> >> >> >> To: Subhash Jadavani
>> >> >> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-
>> samsung-
>> >> >> >> soc@vger.kernel.org; Chris Ball
>> >> >> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC
>> >> 4.5
>> >> >> >>
>> >> >> >> On 1 December 2011 15:33, Subhash Jadavani
>> >> <subhashj@codeaurora.org>
>> >> >> >> wrote:
>> >> >> >> > Hi Girish,
>> >> >> >> >
>> >> >> >> >> -----Original Message-----
>> >> >> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>> >> >> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
>> >> >> >> >> Sent: Wednesday, November 30, 2011 2:24 PM
>> >> >> >> >> To: linux-mmc@vger.kernel.org
>> >> >> >> >> Cc: patches@linaro.org; linux-samsung-soc@vger.kernel.org;
>> >> >> >> >> subhashj@codeaurora.org; Girish K S; Chris Ball
>> >> >> >> >> Subject: [PATCH V5] mmc: core: HS200 mode support for eMMC
>> 4.5
>> >> >> >> >>
>> >> >> >> >> This patch adds the support of the HS200 bus speed for eMMC
>> >> 4.5
>> >> >> >> >> devices.
>> >> >> >> >> The eMMC 4.5 devices have support for 200MHz bus speed.The
>> mmc
>> >> >> core
>> >> >> >> and
>> >> >> >> >> host modules have been touched to add support for this
>> module.
>> >> >> >> >>
>> >> >> >> >> It is necessary to know the card type in the sdhci.c file
>> to
>> >> add
>> >> >> >> >> support
>> >> >> >> >> for eMMC tuning function. So card.h file is included to
>> import
>> >> >> the
>> >> >> >> card
>> >> >> >> >> data structure.
>> >> >> >> >>
>> >> >> >> >> cc: Chris Ball <cjb@laptop.org>
>> >> >> >> >> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
>> >> >> >> >> ---
>> >> >> >> >> Changes in v5:
>> >> >> >> >>       Reduced the case statements for better code
>> readability.
>> >> >> >> Removed
>> >> >> >> >>       unused macro definitions. Modified the tuning
>> function
>> >> >> >> prototype
>> >> >> >> >>       and definition to support tuning for both SD and eMMC
>> >> >> cards.
>> >> >> >> >> Changes in v4:
>> >> >> >> >>       Rebased onto chris-mmc/mmc-next branch. This patch is
>> >> >> >> >> successfully
>> >> >> >> >>       applied on commit with id
>> >> >> >> >> de022ed3fdc14808299b2fa66dbb1ed5ab921912.
>> >> >> >> >> Changes in v3:
>> >> >> >> >>       In the previous commits of chris-mmc/mmc-next branch,
>> >> the
>> >> >> >> patch
>> >> >> >> >> with
>> >> >> >> >>       commit id (c0f22a2c92e357e7cb3988b0b13034d70b7461f9)
>> >> >> defines
>> >> >> >> >> caps2 for
>> >> >> >> >>       more capabilities. This patch version deletes the
>> member
>> >> >> >> >> ext_caps(created
>> >> >> >> >>       in my earlier patch) from struct mmc_host and reuses
>> >> >> already
>> >> >> >> >> accepted
>> >> >> >> >>       caps2 member.
>> >> >> >> >> Changes in v2:
>> >> >> >> >>       Rebased to latest chris-mmc/mmc-next branch. Resolved
>> >> >> >> indentation
>> >> >> >> >>       problems identified in review. This patch has to be
>> >> applied
>> >> >> >> >> before
>> >> >> >> >>       the patch released for modifying the printk messages.
>> >> >> >> >> Changes in v1:
>> >> >> >> >>       Case statements in switch that produce same result
>> have
>> >> >> >> >>       been combined to reduce repeated assignments.
>> >> >> >> >>       patch recreated after rebase to chris balls mmc-next
>> >> >> branch.
>> >> >> >> >>
>> >> >> >> >>  drivers/mmc/core/bus.c    |    3 +-
>> >> >> >> >>  drivers/mmc/core/mmc.c    |   77
>> >> >> >> >> ++++++++++++++++++++++++++++++++++++++++----
>> >> >> >> >>  drivers/mmc/core/sd.c     |    3 +-
>> >> >> >> >>  drivers/mmc/core/sdio.c   |    4 ++-
>> >> >> >> >>  drivers/mmc/host/sdhci.c  |   38 +++++++++++++++++-----
>> >> >> >> >>  include/linux/mmc/card.h  |    3 ++
>> >> >> >> >>  include/linux/mmc/host.h  |   11 ++++++-
>> >> >> >> >>  include/linux/mmc/mmc.h   |   66
>> >> >> >> >> ++++++++++++++++++++++++++++++++++++++-
>> >> >> >> >>  include/linux/mmc/sdhci.h |    1 +
>> >> >> >> >>  9 files changed, 185 insertions(+), 21 deletions(-)
>> >> >> >> >>
>> >> >> >> >> diff --git a/drivers/mmc/core/bus.c
>> b/drivers/mmc/core/bus.c
>> >> >> >> >> index 5639fdf..83c9f8d 100644
>> >> >> >> >> --- a/drivers/mmc/core/bus.c
>> >> >> >> >> +++ b/drivers/mmc/core/bus.c
>> >> >> >> >> @@ -301,10 +301,11 @@ int mmc_add_card(struct mmc_card
>> *card)
>> >> >> >> >>                       mmc_card_ddr_mode(card) ? "DDR " :
>> "",
>> >> >> >> >>                       type);
>> >> >> >> >>       } else {
>> >> >> >> >> -             printk(KERN_INFO "%s: new %s%s%s card at
>> address
>> >> >> >> %04x\n",
>> >> >> >> >> +             pr_info("%s: new %s%s%s%s card at address
>> >> %04x\n",
>> >> >> >> >>                       mmc_hostname(card->host),
>> >> >> >> >>                       mmc_card_uhs(card) ? "ultra high
>> speed "
>> >> :
>> >> >> >> >>                       (mmc_card_highspeed(card) ? "high
>> speed
>> >> " :
>> >> >> >> ""),
>> >> >> >> >> +                     (mmc_card_hs200(card) ? "HS200 " :
>> ""),
>> >> >> >> >>                       mmc_card_ddr_mode(card) ? "DDR " :
>> "",
>> >> >> >> >>                       type, card->rca);
>> >> >> >> >>       }
>> >> >> >> >> diff --git a/drivers/mmc/core/mmc.c
>> b/drivers/mmc/core/mmc.c
>> >> >> >> >> index a1223bd..f4124d6 100644
>> >> >> >> >> --- a/drivers/mmc/core/mmc.c
>> >> >> >> >> +++ b/drivers/mmc/core/mmc.c
>> >> >> >> >> @@ -285,6 +285,27 @@ static int mmc_read_ext_csd(struct
>> >> mmc_card
>> >> >> >> *card,
>> >> >> >> >> u8 *ext_csd)
>> >> >> >> >>       }
>> >> >> >> >>       card->ext_csd.raw_card_type =
>> >> ext_csd[EXT_CSD_CARD_TYPE];
>> >> >> >> >>       switch (ext_csd[EXT_CSD_CARD_TYPE] &
>> >> >> EXT_CSD_CARD_TYPE_MASK) {
>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL:
>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
>> >> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
>> >> >> >> >> +             card->ext_csd.card_type =
>> >> >> EXT_CSD_CARD_TYPE_SDR_200;
>> >> >> >> >> +             break;
>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
>> >> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
>> >> >> >> >> +             card->ext_csd.card_type =
>> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V;
>> >> >> >> >> +             break;
>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
>> >> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
>> >> >> >> >> +             card->ext_csd.card_type =
>> >> >> EXT_CSD_CARD_TYPE_SDR_1_8V;
>> >> >> >> >> +             break;
>> >> >> >> >>       case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52
>> |
>> >> >> >> >>            EXT_CSD_CARD_TYPE_26:
>> >> >> >> >>               card->ext_csd.hs_max_dtr = 52000000;
>> >> >> >> >> @@ -699,6 +720,7 @@ static int mmc_init_card(struct
>> mmc_host
>> >> >> *host,
>> >> >> >> u32
>> >> >> >> >> ocr,
>> >> >> >> >>  {
>> >> >> >> >>       struct mmc_card *card;
>> >> >> >> >>       int err, ddr = 0;
>> >> >> >> >> +     int hs_sdr = 0;
>> >> >> >> >>       u32 cid[4];
>> >> >> >> >>       unsigned int max_dtr;
>> >> >> >> >>       u32 rocr;
>> >> >> >> >> @@ -894,11 +916,16 @@ static int mmc_init_card(struct
>> mmc_host
>> >> >> >> *host,
>> >> >> >> >> u32 ocr,
>> >> >> >> >>       /*
>> >> >> >> >>        * Activate high speed (if supported)
>> >> >> >> >>        */
>> >> >> >> >> -     if ((card->ext_csd.hs_max_dtr != 0) &&
>> >> >> >> >> -             (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
>> >> >> >> >> -             err = mmc_switch(card,
>> EXT_CSD_CMD_SET_NORMAL,
>> >> >> >> >> -                              EXT_CSD_HS_TIMING, 1,
>> >> >> >> >> -                              card-
>> >> >ext_csd.generic_cmd6_time);
>> >> >> >> >> +     if (card->ext_csd.hs_max_dtr != 0) {
>> >> >> >> >> +             err = 0;
>> >> >> >> >> +             if ((card->ext_csd.hs_max_dtr > 52000000) &&
>> >> >> >> >> +                 (host->caps2 & MMC_CAP2_HS200))
>> >> >> >> >> +                     err = mmc_switch(card,
>> >> >> EXT_CSD_CMD_SET_NORMAL,
>> >> >> >> >> +                                      EXT_CSD_HS_TIMING,
>> 2,
>> >> 0);
>> >> >> >> >> +             else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
>> >> >> >> >> +                     err = mmc_switch(card,
>> >> >> EXT_CSD_CMD_SET_NORMAL,
>> >> >> >> >> +                                      EXT_CSD_HS_TIMING,
>> 1,
>> >> 0);
>> >> >> >> >> +
>> >> >> >> >>               if (err && err != -EBADMSG)
>> >> >> >> >>                       goto free_card;
>> >> >> >> >>
>> >> >> >> >> @@ -907,7 +934,11 @@ static int mmc_init_card(struct
>> mmc_host
>> >> >> *host,
>> >> >> >> >> u32 ocr,
>> >> >> >> >>                              mmc_hostname(card->host));
>> >> >> >> >>                       err = 0;
>> >> >> >> >>               } else {
>> >> >> >> >> -                     mmc_card_set_highspeed(card);
>> >> >> >> >> +                     if ((card->ext_csd.hs_max_dtr >
>> >> 52000000)
>> >> >> &&
>> >> >> >> >> +                         (host->caps2 & MMC_CAP2_HS200))
>> >> >> >> >> +                             mmc_card_set_hs200(card);
>> >> >> >> >> +                     else
>> >> >> >> >> +                             mmc_card_set_highspeed(card);
>> >> >> >> >>                       mmc_set_timing(card->host,
>> >> >> MMC_TIMING_MMC_HS);
>> >> >> >> >
>> >> >> >> > MMC_TIMING_MMC_HS200 is defined but still not used.
>> >> >> >> >
>> >> >> >> > So I guess it should be like this ::
>> >> >> >> >  +                      if ((card->ext_csd.hs_max_dtr >
>> >> 52000000)
>> >> >> &&
>> >> >> >> >  +                          (host->caps2 & MMC_CAP2_HS200))
>> {
>> >> >> >> >  +                              mmc_card_set_hs200(card);
>> >> >> >> >  +                      mmc_set_timing(card->host,
>> >> >> >> MMC_TIMING_MMC_HS200)
>> >> >> >> >  +                      } else {
>> >> >> >> >  +
>>  mmc_card_set_highspeed(card);
>> >> >> >> >  +                              mmc_set_timing(card->host,
>> >> >> >> > MMC_TIMING_MMC_HS)
>> >> >> >> >  +                      }
>> >> >> >> >
>> >> >> >> >
>> >> >> >> >
>> >> >> >> >
>> >> >> >> >
>> >> >> >> >
>> >> >> >> >
>> >> >> >> >
>> >> >> >> >
>> >> >> >> >
>> >> >> >> >
>> >> >> >> >
>> >> >> >> >
>> >> >> >> >
>> >> >> >> >>               }
>> >> >> >> >>       }
>> >> >> >> >> @@ -933,7 +964,7 @@ static int mmc_init_card(struct
>> mmc_host
>> >> >> *host,
>> >> >> >> u32
>> >> >> >> >> ocr,
>> >> >> >> >>        */
>> >> >> >> >>       max_dtr = (unsigned int)-1;
>> >> >> >> >>
>> >> >> >> >> -     if (mmc_card_highspeed(card)) {
>> >> >> >> >> +     if (mmc_card_highspeed(card) || mmc_card_hs200(card))
>> {
>> >> >> >> >>               if (max_dtr > card->ext_csd.hs_max_dtr)
>> >> >> >> >>                       max_dtr = card->ext_csd.hs_max_dtr;
>> >> >> >> >>       } else if (max_dtr > card->csd.max_dtr) {
>> >> >> >> >> @@ -959,6 +990,18 @@ static int mmc_init_card(struct
>> mmc_host
>> >> >> *host,
>> >> >> >> >> u32 ocr,
>> >> >> >> >>       }
>> >> >> >> >>
>> >> >> >> >>       /*
>> >> >> >> >> +      * Indicate HS200 SDR mode (if supported).
>> >> >> >> >> +      */
>> >> >> >> >> +     if (mmc_card_hs200(card)) {
>> >> >> >> >> +             if ((card->ext_csd.card_type &
>> >> >> >> EXT_CSD_CARD_TYPE_SDR_1_8V)
>> >> >> >> >> +                     && (host->caps2 &
>> >> MMC_CAP2_HS200_1_8V_SDR))
>> >> >> >> >> +                             hs_sdr = MMC_1_8V_SDR_MODE;
>> >> >> >> >> +             else if ((card->ext_csd.card_type &
>> >> >> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
>> >> >> >> >> +                     && (host->caps2 &
>> >> MMC_CAP2_HS200_1_2V_SDR))
>> >> >> >> >> +                             hs_sdr = MMC_1_2V_SDR_MODE;
>> >> >> >> >> +     }
>> >> >> >> >> +
>> >> >> >> >> +     /*
>> >> >> >> >>        * Activate wide bus and DDR (if supported).
>> >> >> >> >>        */
>> >> >> >> >>       if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
>> >> >> >> >> @@ -998,6 +1041,17 @@ static int mmc_init_card(struct
>> mmc_host
>> >> >> >> *host,
>> >> >> >> >> u32 ocr,
>> >> >> >> >>                       if (!err) {
>> >> >> >> >>                               mmc_set_bus_width(card->host,
>> >> >> >> bus_width);
>> >> >> >> >>
>> >> >> >> >> +                             if ((host->caps2 &
>> >> MMC_CAP2_HS200)
>> >> >> &&
>> >> >> >> >> +                                 card->host->ops-
>> >> >> >execute_tuning)
>> >> >> >> >> +                                     err = card->host-
>> >ops->
>> >> \
>> >> >> >> >> +
>> >> execute_tuning(card-
>> >> >> >> >host,
>> >> >> >> >> +
>> >> >> >> > MMC_SEND_TUNING_BLOCK_HS200);
>> >> >> >> >
>> >> >> >> >
>> >> >> >> > execute_tuning should be done right after the timing is
>> changed
>> >> to
>> >> >> >> HS200 and
>> >> >> >> > clock rate is changed to 200Mhz. This is not the correct
>> >> sequence
>> >> >> to
>> >> >> >> call
>> >> >> >> > the execute_tuning().
>> >> >> >> > As told earlier, It is mentioned in the spec that tuning
>> should
>> >> be
>> >> >> >> executed after change of buswidth (mandatory). Also it
>> mentions
>> >> that
>> >> >> >> "The host may invoke the HS200 tuning sequence, by sending
>> CMD21
>> >> to
>> >> >> the
>> >> >> >> device". It means that
>> >> >> >>  after setting the HS200 mode, Changing to freq > 52Mhz and
>> >> changing
>> >> >> >> the bus width tuning can be executed anytime to identify the
>> >> >> sampling
>> >> >> >> point to read.(By anytime i mean before actual block read
>> >> >> Operation).
>> >> >> >> Can you please point me to the place in the spec where it
>> >> specifies
>> >> >> >> tuning should be done immediately after freq change (may be i
>> >> missed
>> >> >> >> to read it).
>> >> >> >
>> >> >> >
>> >> >> > Ok. let me ask you this. Why do we run the execute_tuning()?
>> It's
>> >> to
>> >> >> tune
>> >> >> > the sampling clock generator of host controller before you
>> start
>> >> any
>> >> >> read
>> >> >> > operation (on command line or data line) from card. If you
>> don't
>> >> tune
>> >> >> the
>> >> >> > sampling clock generator before the read operation (after
>> changing
>> >> >> the
>> >> >> > timing to HS200 and clock rate to 200mhz), you can't be sure
>> that
>> >> >> read
>> >> >> > operation from card will be completed without errors. You may
>> get
>> >> the
>> >> >> data /
>> >> >> > cmd response CRC errors. At least this will surely fail on our
>> MSM
>> >> >> SDCC host
>> >> >> > controller. That's what we had faced with SD3.0 UHS-I tuning as
>> >> well
>> >> >> as
>> >> >> > mentioned in http://www.spinics.net/lists/linux-arm-
>> >> >> msm/msg03867.html.
>> >> >
>> >> >> > this tuning is done before any read opration for the best bus
>> >> width
>> >> >> supported.
>> >> > Agreed. But can we be sure that "command response" for bus width
>> >> change via
>> >> > CMD6, will not have any command CRC failures if tuning is not
>> done?
>> >> All responses are sent on CMD line not on data lines, And sampling
>> is
>> >> done for Data lines before reading. So command CRC failure doesnt
>> >> depend on tuning. If you get error during CMD6 it could be that
>> device
>> >> cannot support the bus width at the set frequency.
>> >
>> > I guess it's not the correct assumption here. Sampling point tuning
>> is to
>> Its Not assumption "Specification says responses are all sent on CMD
>> only"
>
>
>
> Where does it say that tuning is not required for data received on command
> line? If the 200Mhz clock can effect the data received on DATA lines then
> why it won't affect the data (responses) received on CMD lines?
> If you still have doubt, I would suggest to get the clarification from
> JEDEC.  From SD3.01 spec, for sure CMD lines also requires tuning.
>
> "Sampling clock generation" on our host controller also says that tuning is
> required for data transfer on both DATA and CMD lines.
>
> I am not sure what is the issue with doing the tuning immediately after
> changing to bus speed mode to HS200 (changing controller timing, changing
> clock etc ...)? This is what we are doing it for SD3.0 cards as well.
>
> Your current implementation is not going to work with all host controllers.
>
>
>
>
>
>
>> > tune the sampling point for data received on both CMD and DATA lines
>> (not
>> > just data lines). I can't find detailed mentioning of this in eMMC4.5
>> Pls check the section 6.6.7.1. the 2nd paragraph quotes "which in turn
>> uses it to find the
>> optimal sampling point for the data lines"
>> > (that's the documentation short coming, you can even confirm whether
>> tuning
>> > procedure is required for CMD line or not from JEDEC) but SD3.01
>> > specification does mention this tuning procedure in great details.
>> NOTE:
>> > eMMC4.5 HS200 mode is mostly inspired from SD3.01 UHS-I bus speed
>> modes.
>> >
>> > Section " 4.2.4.5 Tuning Command" in "SD3.01 - Simplified
>> >
>> (Part_1_Physical_Layer_Simplified_Specification_Ver_3.01_Final_100518)"
>> > specification(can be downloaded from here:
>> > https://www.sdcard.org/downloads/pls/), clearly states this:
>> >
>> > 4.2.4.5 Tuning Command
>> > CMD19 is defined for Send Tuning Block Command. R1 type response is
>> defined.
>> > CMD19 can be
>> > executed in transfer state of 1.8V signaling mode while the card is
>> > unlocked. The other case, CMD19 is
>> > treated as illegal command. Data block, carried by DAT[3:0], contains
>> a
>> > pattern for tuning sampling
>> > position to receive data on the CMD and DAT[3:0] line. The block
>> length of
>> > CMD19 is fixed and CMD16
>> > is not required.
>> > I have no idea of the SD spec. I have just seen the eMMC spec and
>> above quotes might answer your doubt
>> > So before tuning, you may get the Command CRC errors in HS200 mode.
>> >
>> > Regards,
>> > Subhash
>> >
>> >> >
>> >> >> ps:Chris need your comment on this
>> >> >> >
>> >> >> >> >> +
>> >> >> >> >> +                             if (err) {
>> >> >> >> >> +                                     pr_warning("tuning
>> >> >> execution
>> >> >> >> > failed\n");
>> >> >> >> >> +                                     continue;
>> >> >> >> >> +                             }
>> >> >> >> >> +
>> >> >> >> >>                               /*
>> >> >> >> >>                                * If controller can't handle
>> >> bus
>> >> >> >> width
>> >> >> >> > test,
>> >> >> >> >>                                * compare ext_csd previously
>> >> read
>> >> >> in
>> >> >> >> 1 bit
>> >> >> >> >> mode
>> >> >> >> >> @@ -1056,6 +1110,15 @@ static int mmc_init_card(struct
>> >> mmc_host
>> >> >> >> *host,
>> >> >> >> >> u32 ocr,
>> >> >> >> >>                       mmc_card_set_ddr_mode(card);
>> >> >> >> >>                       mmc_set_timing(card->host,
>> >> >> >> MMC_TIMING_UHS_DDR50);
>> >> >> >> >>                       mmc_set_bus_width(card->host,
>> >> bus_width);
>> >> >> >> >> +             } else if (hs_sdr) {
>> >> >> >> >> +                     if (hs_sdr ==
>> >> EXT_CSD_CARD_TYPE_SDR_1_2V) {
>> >> >> >> >> +                             err =
>> >> mmc_set_signal_voltage(host,
>> >> >> >> >> +
>> MMC_SIGNAL_VOLTAGE_120,
>> >> 0);
>> >> >> >> >> +                             if (err)
>> >> >> >> >> +                                     goto err;
>> >> >> >> >> +                     }
>> >> >> >> >> +                     mmc_set_timing(card->host,
>> >> >> MMC_TIMING_MMC_HS);
>> >> >> >> >> +                     mmc_set_bus_width(card->host,
>> >> bus_width);
>> >> >> >> >>               }
>> >> >> >> >>       }
>> >> >> >> >>
>> >> >> >> >> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
>> >> >> >> >> index 1d5a3bd..c1d3ee3 100644
>> >> >> >> >> --- a/drivers/mmc/core/sd.c
>> >> >> >> >> +++ b/drivers/mmc/core/sd.c
>> >> >> >> >> @@ -660,7 +660,8 @@ static int mmc_sd_init_uhs_card(struct
>> >> >> mmc_card
>> >> >> >> >> *card)
>> >> >> >> >>
>> >> >> >> >>       /* SPI mode doesn't define CMD19 */
>> >> >> >> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
>> >> >> >> >> >execute_tuning)
>> >> >> >> >> -             err = card->host->ops->execute_tuning(card-
>> >> >host);
>> >> >> >> >> +             err = card->host->ops->execute_tuning(card-
>> >> >host,
>> >> >> >>   \
>> >> >> >> >> +
>> >> >> >> > MMC_SEND_TUNING_BLOCK);
>> >> >> >> >>
>> >> >> >> >>  out:
>> >> >> >> >>       kfree(status);
>> >> >> >> >> diff --git a/drivers/mmc/core/sdio.c
>> b/drivers/mmc/core/sdio.c
>> >> >> >> >> index 8c04f7f..8ef8817 100644
>> >> >> >> >> --- a/drivers/mmc/core/sdio.c
>> >> >> >> >> +++ b/drivers/mmc/core/sdio.c
>> >> >> >> >> @@ -14,6 +14,7 @@
>> >> >> >> >>
>> >> >> >> >>  #include <linux/mmc/host.h>
>> >> >> >> >>  #include <linux/mmc/card.h>
>> >> >> >> >> +#include <linux/mmc/mmc.h>
>> >> >> >> >>  #include <linux/mmc/sdio.h>
>> >> >> >> >>  #include <linux/mmc/sdio_func.h>
>> >> >> >> >>  #include <linux/mmc/sdio_ids.h>
>> >> >> >> >> @@ -556,7 +557,8 @@ static int
>> mmc_sdio_init_uhs_card(struct
>> >> >> >> mmc_card
>> >> >> >> >> *card)
>> >> >> >> >>
>> >> >> >> >>       /* Initialize and start re-tuning timer */
>> >> >> >> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
>> >> >> >> >> >execute_tuning)
>> >> >> >> >> -             err = card->host->ops->execute_tuning(card-
>> >> >host);
>> >> >> >> >> +             err = card->host->ops->execute_tuning(card-
>> >> >host,
>> >> >> >> >> +
>> >> >> >> > MMC_SEND_TUNING_BLOCK);
>> >> >> >> >>
>> >> >> >> >>  out:
>> >> >> >> >>
>> >> >> >> >> diff --git a/drivers/mmc/host/sdhci.c
>> >> b/drivers/mmc/host/sdhci.c
>> >> >> >> >> index a7c2311..13d74bb 100644
>> >> >> >> >> --- a/drivers/mmc/host/sdhci.c
>> >> >> >> >> +++ b/drivers/mmc/host/sdhci.c
>> >> >> >> >> @@ -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
>> >> >> >> >> @@ -1016,7 +1016,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
>> >> >> */
>> >> >> >> >> @@ -1673,7 +1674,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;
>> >> >> >> >> @@ -1694,10 +1695,13 @@ static int
>> sdhci_execute_tuning(struct
>> >> >> >> mmc_host
>> >> >> >> >> *mmc)
>> >> >> >> >>        * Host Controller needs tuning only in case of
>> SDR104
>> >> mode
>> >> >> >> >>        * and for SDR50 mode when Use Tuning for SDR50 is
>> set
>> >> in
>> >> >> >> >>        * Capabilities register.
>> >> >> >> >> +      * If the Host Controller supports the HS200 mode
>> then
>> >> >> tuning
>> >> >> >> >> +      * function has to be executed.
>> >> >> >> >>        */
>> >> >> >> >>       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)))
>> >> >> >> >> +         (host->flags & SDHCI_SDR50_NEEDS_TUNING)) ||
>> >> >> >> >> +         (host->flags & SDHCI_HS200_NEEDS_TUNING))
>> >> >> >> >>               ctrl |= SDHCI_CTRL_EXEC_TUNING;
>> >> >> >> >>       else {
>> >> >> >> >>               spin_unlock(&host->lock);
>> >> >> >> >> @@ -1733,7 +1737,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;
>> >> >> >> >> @@ -1748,7 +1752,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.
>> >> >> >> >> @@ -2131,12 +2145,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;
>> >> >> >> >> @@ -2741,6 +2757,10 @@ int sdhci_add_host(struct sdhci_host
>> >> >> *host)
>> >> >> >> >>       if (caps[1] & SDHCI_USE_SDR50_TUNING)
>> >> >> >> >>               host->flags |= SDHCI_SDR50_NEEDS_TUNING;
>> >> >> >> >>
>> >> >> >> >> +     /* Does the host needs 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;
>> >> >> >> >> diff --git a/include/linux/mmc/card.h
>> >> b/include/linux/mmc/card.h
>> >> >> >> >> index 534974c..e76f649 100644
>> >> >> >> >> --- a/include/linux/mmc/card.h
>> >> >> >> >> +++ b/include/linux/mmc/card.h
>> >> >> >> >> @@ -209,6 +209,7 @@ struct mmc_card {
>> >> >> >> >>  #define MMC_STATE_HIGHSPEED_DDR (1<<4)               /*
>> card
>> >> is
>> >> >> in
>> >> >> >> high
>> >> >> >> >> speed mode */
>> >> >> >> >>  #define MMC_STATE_ULTRAHIGHSPEED (1<<5)              /*
>> card
>> >> is
>> >> >> in
>> >> >> >> ultra
>> >> >> >> >> high speed mode */
>> >> >> >> >>  #define MMC_CARD_SDXC                (1<<6)          /*
>> card
>> >> is
>> >> >> >> SDXC */
>> >> >> >> >> +#define MMC_STATE_HIGHSPEED_200      (1<<7)  /* card is in
>> >> HS200
>> >> >> >> >> mode */
>> >> >> >> >>       unsigned int            quirks;         /* card
>> quirks
>> >> */
>> >> >> >> >>  #define MMC_QUIRK_LENIENT_FN0        (1<<0)          /*
>> allow
>> >> >> SDIO
>> >> >> >> FN0
>> >> >> >> >> writes outside of the VS CCCR range */
>> >> >> >> >>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func-
>> >> >> >> >> >cur_blksize */
>> >> >> >> >> @@ -365,6 +366,7 @@ static inline void __maybe_unused
>> >> >> >> >> remove_quirk(struct mmc_card *card, int data)
>> >> >> >> >>  #define mmc_card_present(c)  ((c)->state &
>> MMC_STATE_PRESENT)
>> >> >> >> >>  #define mmc_card_readonly(c) ((c)->state &
>> >> MMC_STATE_READONLY)
>> >> >> >> >>  #define mmc_card_highspeed(c)        ((c)->state &
>> >> >> >> MMC_STATE_HIGHSPEED)
>> >> >> >> >> +#define mmc_card_hs200(c)    ((c)->state &
>> >> >> MMC_STATE_HIGHSPEED_200)
>> >> >> >> >>  #define mmc_card_blockaddr(c)        ((c)->state &
>> >> >> >> MMC_STATE_BLOCKADDR)
>> >> >> >> >>  #define mmc_card_ddr_mode(c) ((c)->state &
>> >> >> MMC_STATE_HIGHSPEED_DDR)
>> >> >> >> >>  #define mmc_card_uhs(c)              ((c)->state &
>> >> >> >> >> MMC_STATE_ULTRAHIGHSPEED)
>> >> >> >> >> @@ -374,6 +376,7 @@ static inline void __maybe_unused
>> >> >> >> >> remove_quirk(struct mmc_card *card, int data)
>> >> >> >> >>  #define mmc_card_set_present(c)      ((c)->state |=
>> >> >> >> MMC_STATE_PRESENT)
>> >> >> >> >>  #define mmc_card_set_readonly(c) ((c)->state |=
>> >> >> MMC_STATE_READONLY)
>> >> >> >> >>  #define mmc_card_set_highspeed(c) ((c)->state |=
>> >> >> >> MMC_STATE_HIGHSPEED)
>> >> >> >> >> +#define mmc_card_set_hs200(c)        ((c)->state |=
>> >> >> >> >> MMC_STATE_HIGHSPEED_200)
>> >> >> >> >>  #define mmc_card_set_blockaddr(c) ((c)->state |=
>> >> >> >> MMC_STATE_BLOCKADDR)
>> >> >> >> >>  #define mmc_card_set_ddr_mode(c) ((c)->state |=
>> >> >> >> >> MMC_STATE_HIGHSPEED_DDR)
>> >> >> >> >>  #define mmc_card_set_uhs(c) ((c)->state |=
>> >> >> >> MMC_STATE_ULTRAHIGHSPEED)
>> >> >> >> >> diff --git a/include/linux/mmc/host.h
>> >> b/include/linux/mmc/host.h
>> >> >> >> >> index 706f722..5eac57a 100644
>> >> >> >> >> --- a/include/linux/mmc/host.h
>> >> >> >> >> +++ b/include/linux/mmc/host.h
>> >> >> >> >> @@ -50,6 +50,7 @@ struct mmc_ios {
>> >> >> >> >>
>> >> >> >> >>  #define MMC_TIMING_LEGACY    0
>> >> >> >> >>  #define MMC_TIMING_MMC_HS    1
>> >> >> >> >> +#define MMC_TIMING_MMC_HS200 2
>> >> >> >> >>  #define MMC_TIMING_SD_HS     2
>> >> >> >> >>  #define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY
>> >> >> >> >>  #define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS
>> >> >> >> >> @@ -60,6 +61,8 @@ struct mmc_ios {
>> >> >> >> >>  #define MMC_SDR_MODE         0
>> >> >> >> >>  #define MMC_1_2V_DDR_MODE    1
>> >> >> >> >>  #define MMC_1_8V_DDR_MODE    2
>> >> >> >> >> +#define MMC_1_2V_SDR_MODE    3
>> >> >> >> >> +#define MMC_1_8V_SDR_MODE    4
>> >> >> >> >>
>> >> >> >> >>       unsigned char   signal_voltage;         /* signalling
>> >> >> voltage
>> >> >> >> >> (1.8V or 3.3V) */
>> >> >> >> >>
>> >> >> >> >> @@ -148,7 +151,9 @@ struct mmc_host_ops {
>> >> >> >> >>       void    (*init_card)(struct mmc_host *host, struct
>> >> mmc_card
>> >> >> >> *card);
>> >> >> >> >>
>> >> >> >> >>       int     (*start_signal_voltage_switch)(struct
>> mmc_host
>> >> >> *host,
>> >> >> >> >> struct mmc_ios *ios);
>> >> >> >> >> -     int     (*execute_tuning)(struct mmc_host *host);
>> >> >> >> >> +
>> >> >> >> >> +     /* The tuning command opcode value is different for
>> SD
>> >> and
>> >> >> >> eMMC
>> >> >> >> >> cards */
>> >> >> >> >> +     int     (*execute_tuning)(struct mmc_host *host, u32
>> >> >> opcode);
>> >> >> >> >>       void    (*enable_preset_value)(struct mmc_host *host,
>> >> bool
>> >> >> >> enable);
>> >> >> >> >>       int     (*select_drive_strength)(unsigned int
>> max_dtr,
>> >> int
>> >> >> >> >> host_drv, int card_drv);
>> >> >> >> >>       void    (*hw_reset)(struct mmc_host *host);
>> >> >> >> >> @@ -242,6 +247,10 @@ struct mmc_host {
>> >> >> >> >>  #define MMC_CAP2_CACHE_CTRL  (1 << 1)        /* Allow
>> cache
>> >> >> control
>> >> >> >> */
>> >> >> >> >>  #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)    /* Notify
>> >> poweroff
>> >> >> >> >> supported */
>> >> >> >> >>  #define MMC_CAP2_NO_MULTI_READ       (1 << 3)        /*
>> >> >> Multiblock
>> >> >> >> reads
>> >> >> >> >> don't work */
>> >> >> >> >> +#define MMC_CAP2_HS200_1_8V_SDR      (1 << 4)        /*
>> can
>> >> >> support
>> >> >> >> */
>> >> >> >> >> +#define MMC_CAP2_HS200_1_2V_SDR      (1 << 5)        /*
>> can
>> >> >> support
>> >> >> >> */
>> >> >> >> >> +#define MMC_CAP2_HS200
>> (MMC_CAP2_HS200_1_8V_SDR
>> >> |
>> >> >> \
>> >> >> >> >> +                              MMC_CAP2_HS200_1_2V_SDR)
>> >> >> >> >>
>> >> >> >> >>       mmc_pm_flag_t           pm_caps;        /* supported
>> pm
>> >> >> >> features */
>> >> >> >> >>       unsigned int        power_notify_type;
>> >> >> >> >> diff --git a/include/linux/mmc/mmc.h
>> b/include/linux/mmc/mmc.h
>> >> >> >> >> index 0e71356..7996272 100644
>> >> >> >> >> --- a/include/linux/mmc/mmc.h
>> >> >> >> >> +++ b/include/linux/mmc/mmc.h
>> >> >> >> >> @@ -51,6 +51,7 @@
>> >> >> >> >>  #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data
>> >> addr
>> >> >> R1
>> >> >> >> >> */
>> >> >> >> >>  #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data
>> >> addr
>> >> >> R1
>> >> >> >> >> */
>> >> >> >> >>  #define MMC_SEND_TUNING_BLOCK    19   /* adtc
>> >> >>  R1
>> >> >> >> >> */
>> >> >> >> >> +#define MMC_SEND_TUNING_BLOCK_HS200  21      /* adtc R1
>>  */
>> >> >> >> >>
>> >> >> >> >>    /* class 3 */
>> >> >> >> >>  #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data
>> >> addr
>> >> >> R1
>> >> >> >> >> */
>> >> >> >> >> @@ -333,13 +334,76 @@ struct _mmc_csd {
>> >> >> >> >>
>> >> >> >> >>  #define EXT_CSD_CARD_TYPE_26 (1<<0)  /* Card can run at
>> 26MHz
>> >> */
>> >> >> >> >>  #define EXT_CSD_CARD_TYPE_52 (1<<1)  /* Card can run at
>> 52MHz
>> >> */
>> >> >> >> >> -#define EXT_CSD_CARD_TYPE_MASK       0xF     /* Mask out
>> >> >> reserved
>> >> >> >> bits */
>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_MASK       0x3F    /* Mask out
>> >> >> reserved
>> >> >> >> bits */
>> >> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can
>> run
>> >> at
>> >> >> >> 52MHz
>> >> >> >> >> */
>> >> >> >> >>                                            /* DDR mode
>> @1.8V
>> >> or
>> >> >> 3V
>> >> >> >> I/O */
>> >> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can
>> run
>> >> at
>> >> >> >> 52MHz
>> >> >> >> >> */
>> >> >> >> >>                                            /* DDR mode
>> @1.2V
>> >> I/O
>> >> >> */
>> >> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_52
>> >> >> (EXT_CSD_CARD_TYPE_DDR_1_8V
>> >> >> >>  \
>> >> >> >> >>                                       |
>> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V)
>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V   (1<<4)  /* Card can
>> run
>> >> at
>> >> >> >> >> 200MHz */
>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V   (1<<5)  /* Card can
>> run
>> >> at
>> >> >> >> >> 200MHz */
>> >> >> >> >> +                                             /* SDR mode
>> >> @1.2V
>> >> >> I/O
>> >> >> >> */
>> >> >> >> >> +
>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_200
>> >>  (EXT_CSD_CARD_TYPE_SDR_1_8V
>> >> >> >>   \
>> >> >> >> >> +                                     |
>> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
>> >> >> >> >> +
>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL
>> >>  (EXT_CSD_CARD_TYPE_SDR_200
>> >> >> >>  \
>> >> >> >> >> +                                     |
>> EXT_CSD_CARD_TYPE_52
>> >> >> >>  \
>> >> >> >> >> +                                     |
>> EXT_CSD_CARD_TYPE_26)
>> >> >> >> >> +
>> >> >> >> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_2V_ALL
>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V     \
>> >> >> >> >> +                                     |
>> EXT_CSD_CARD_TYPE_52
>> >> >> >>  \
>> >> >> >> >> +                                     |
>> EXT_CSD_CARD_TYPE_26)
>> >> >> >> >> +
>> >> >> >> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_8V_ALL
>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V     \
>> >> >> >> >> +                                     |
>> EXT_CSD_CARD_TYPE_52
>> >> >> >>  \
>> >> >> >> >> +                                     |
>> EXT_CSD_CARD_TYPE_26)
>> >> >> >> >> +
>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V
>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_52
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> >> +
>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V
>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_52
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> >> +
>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V
>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_52
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> >> +
>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V
>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_52
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> >> +
>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52
>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_DDR_52
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_52
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> >> +
>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52
>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_DDR_52
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_52
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> >> +
>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V
>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_52
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> >> +
>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V
>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_52
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> >> +
>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52
>> >> >> >> (EXT_CSD_CARD_TYPE_SDR_200
>> >> >> >> >> \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_DDR_52
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> EXT_CSD_CARD_TYPE_52
>> >> >> >> > \
>> >> >> >> >> +                                             |
>> >> >> >> EXT_CSD_CARD_TYPE_26)
>> >> >> >> >>
>> >> >> >> >>  #define EXT_CSD_BUS_WIDTH_1  0       /* Card is in 1 bit
>> mode
>> >> */
>> >> >> >> >>  #define EXT_CSD_BUS_WIDTH_4  1       /* Card is in 4 bit
>> mode
>> >> */
>> >> >> >> >> diff --git a/include/linux/mmc/sdhci.h
>> >> >> b/include/linux/mmc/sdhci.h
>> >> >> >> >> index e4b6935..d9a2222 100644
>> >> >> >> >> --- a/include/linux/mmc/sdhci.h
>> >> >> >> >> +++ b/include/linux/mmc/sdhci.h
>> >> >> >> >> @@ -121,6 +121,7 @@ struct sdhci_host {
>> >> >> >> >>  #define SDHCI_AUTO_CMD23     (1<<7)  /* Auto CMD23 support
>> */
>> >> >> >> >>  #define SDHCI_PV_ENABLED     (1<<8)  /* Preset value
>> enabled
>> >> */
>> >> >> >> >>  #define SDHCI_SDIO_IRQ_ENABLED       (1<<9)  /* SDIO irq
>> >> enabled
>> >> >> */
>> >> >> >> >> +#define SDHCI_HS200_NEEDS_TUNING (1<<10)     /* HS200
>> needs
>> >> >> tuning
>> >> >> >> */
>> >> >> >> >>
>> >> >> >> >>       unsigned int version;   /* SDHCI spec. version */
>> >> >> >> >>
>> >> >> >> >> --
>> >> >> >> >> 1.7.1
>> >> >> >> >>
>> >> >> >> >> --
>> >> >> >> >> To unsubscribe from this list: send the line "unsubscribe
>> >> linux-
>> >> >> mmc"
>> >> >> >> in
>> >> >> >> >> the body of a message to majordomo@vger.kernel.org
>> >> >> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
>> >> >> info.html
>> >> >> >> >
>> >> >> >> > --
>> >> >> >> > To unsubscribe from this list: send the line "unsubscribe
>> >> linux-
>> >> >> mmc"
>> >> >> >> in
>> >> >> >> > the body of a message to majordomo@vger.kernel.org
>> >> >> >> > More majordomo info at  http://vger.kernel.org/majordomo-
>> >> info.html
>> >> >> >> >
>> >> >> >> --
>> >> >> >> To unsubscribe from this list: send the line "unsubscribe
>> linux-
>> >> mmc"
>> >> >> in
>> >> >> >> the body of a message to majordomo@vger.kernel.org
>> >> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
>> >> info.html
>> >> >> >
>> >> >> --
>> >> >> To unsubscribe from this list: send the line "unsubscribe linux-
>> mmc"
>> >> in
>> >> >> the body of a message to majordomo@vger.kernel.org
>> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
>> info.html
>> >> >
>> >
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Girish K S Dec. 8, 2011, 11:49 a.m. UTC | #11
On 5 December 2011 20:29, Saugata Das <saugata.das@linaro.org> wrote:
> Hi Girish
>
> Please refer to Figure 71 (HS200 device output timing) of the MMC-4.5
> spec. It shows that both CMD and DATA[7-0] will have some latency till
> valid window. This implies that even the CMD line will need tuning for
> reading the response. The specification talks about identifying
> sampling point for data lines by reading tuning blocks. Based on host
> controller capability, even the CMD line will get the good sample
> point during the same tuning sequence.
>Thanks for pointing the right place. will do the necessary changes
> We need to have the tuning done (execute_tuning) soon after switching
> to HS200 mode and 200MHz clock.
>
>
> Regards
> Saugata
>
>
> On 5 December 2011 16:59, Subhash Jadavani <subhashj@codeaurora.org> wrote:
>>
>>
>>> -----Original Message-----
>>> From: Girish K S [mailto:girish.shivananjappa@linaro.org]
>>> Sent: Monday, December 05, 2011 12:20 PM
>>> To: Subhash Jadavani
>>> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>>> soc@vger.kernel.org; Chris Ball
>>> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>>>
>>> On 5 December 2011 11:46, Subhash Jadavani <subhashj@codeaurora.org>
>>> wrote:
>>> >
>>> >
>>> >> -----Original Message-----
>>> >> From: Girish K S [mailto:girish.shivananjappa@linaro.org]
>>> >> Sent: Friday, December 02, 2011 5:08 PM
>>> >> To: Subhash Jadavani
>>> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>>> >> soc@vger.kernel.org; Chris Ball
>>> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>>> >>
>>> >> On 2 December 2011 00:02, Subhash Jadavani <subhashj@codeaurora.org>
>>> >> wrote:
>>> >> >
>>> >> >
>>> >> >> -----Original Message-----
>>> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>>> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
>>> >> >> Sent: Thursday, December 01, 2011 7:48 PM
>>> >> >> To: Subhash Jadavani
>>> >> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>>> >> >> soc@vger.kernel.org; Chris Ball
>>> >> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC
>>> 4.5
>>> >> >>
>>> >> >> On 1 December 2011 16:27, Subhash Jadavani
>>> <subhashj@codeaurora.org>
>>> >> >> wrote:
>>> >> >> >
>>> >> >> >
>>> >> >> >> -----Original Message-----
>>> >> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>>> >> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
>>> >> >> >> Sent: Thursday, December 01, 2011 3:58 PM
>>> >> >> >> To: Subhash Jadavani
>>> >> >> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-
>>> samsung-
>>> >> >> >> soc@vger.kernel.org; Chris Ball
>>> >> >> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC
>>> >> 4.5
>>> >> >> >>
>>> >> >> >> On 1 December 2011 15:33, Subhash Jadavani
>>> >> <subhashj@codeaurora.org>
>>> >> >> >> wrote:
>>> >> >> >> > Hi Girish,
>>> >> >> >> >
>>> >> >> >> >> -----Original Message-----
>>> >> >> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>>> >> >> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
>>> >> >> >> >> Sent: Wednesday, November 30, 2011 2:24 PM
>>> >> >> >> >> To: linux-mmc@vger.kernel.org
>>> >> >> >> >> Cc: patches@linaro.org; linux-samsung-soc@vger.kernel.org;
>>> >> >> >> >> subhashj@codeaurora.org; Girish K S; Chris Ball
>>> >> >> >> >> Subject: [PATCH V5] mmc: core: HS200 mode support for eMMC
>>> 4.5
>>> >> >> >> >>
>>> >> >> >> >> This patch adds the support of the HS200 bus speed for eMMC
>>> >> 4.5
>>> >> >> >> >> devices.
>>> >> >> >> >> The eMMC 4.5 devices have support for 200MHz bus speed.The
>>> mmc
>>> >> >> core
>>> >> >> >> and
>>> >> >> >> >> host modules have been touched to add support for this
>>> module.
>>> >> >> >> >>
>>> >> >> >> >> It is necessary to know the card type in the sdhci.c file
>>> to
>>> >> add
>>> >> >> >> >> support
>>> >> >> >> >> for eMMC tuning function. So card.h file is included to
>>> import
>>> >> >> the
>>> >> >> >> card
>>> >> >> >> >> data structure.
>>> >> >> >> >>
>>> >> >> >> >> cc: Chris Ball <cjb@laptop.org>
>>> >> >> >> >> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
>>> >> >> >> >> ---
>>> >> >> >> >> Changes in v5:
>>> >> >> >> >>       Reduced the case statements for better code
>>> readability.
>>> >> >> >> Removed
>>> >> >> >> >>       unused macro definitions. Modified the tuning
>>> function
>>> >> >> >> prototype
>>> >> >> >> >>       and definition to support tuning for both SD and eMMC
>>> >> >> cards.
>>> >> >> >> >> Changes in v4:
>>> >> >> >> >>       Rebased onto chris-mmc/mmc-next branch. This patch is
>>> >> >> >> >> successfully
>>> >> >> >> >>       applied on commit with id
>>> >> >> >> >> de022ed3fdc14808299b2fa66dbb1ed5ab921912.
>>> >> >> >> >> Changes in v3:
>>> >> >> >> >>       In the previous commits of chris-mmc/mmc-next branch,
>>> >> the
>>> >> >> >> patch
>>> >> >> >> >> with
>>> >> >> >> >>       commit id (c0f22a2c92e357e7cb3988b0b13034d70b7461f9)
>>> >> >> defines
>>> >> >> >> >> caps2 for
>>> >> >> >> >>       more capabilities. This patch version deletes the
>>> member
>>> >> >> >> >> ext_caps(created
>>> >> >> >> >>       in my earlier patch) from struct mmc_host and reuses
>>> >> >> already
>>> >> >> >> >> accepted
>>> >> >> >> >>       caps2 member.
>>> >> >> >> >> Changes in v2:
>>> >> >> >> >>       Rebased to latest chris-mmc/mmc-next branch. Resolved
>>> >> >> >> indentation
>>> >> >> >> >>       problems identified in review. This patch has to be
>>> >> applied
>>> >> >> >> >> before
>>> >> >> >> >>       the patch released for modifying the printk messages.
>>> >> >> >> >> Changes in v1:
>>> >> >> >> >>       Case statements in switch that produce same result
>>> have
>>> >> >> >> >>       been combined to reduce repeated assignments.
>>> >> >> >> >>       patch recreated after rebase to chris balls mmc-next
>>> >> >> branch.
>>> >> >> >> >>
>>> >> >> >> >>  drivers/mmc/core/bus.c    |    3 +-
>>> >> >> >> >>  drivers/mmc/core/mmc.c    |   77
>>> >> >> >> >> ++++++++++++++++++++++++++++++++++++++++----
>>> >> >> >> >>  drivers/mmc/core/sd.c     |    3 +-
>>> >> >> >> >>  drivers/mmc/core/sdio.c   |    4 ++-
>>> >> >> >> >>  drivers/mmc/host/sdhci.c  |   38 +++++++++++++++++-----
>>> >> >> >> >>  include/linux/mmc/card.h  |    3 ++
>>> >> >> >> >>  include/linux/mmc/host.h  |   11 ++++++-
>>> >> >> >> >>  include/linux/mmc/mmc.h   |   66
>>> >> >> >> >> ++++++++++++++++++++++++++++++++++++++-
>>> >> >> >> >>  include/linux/mmc/sdhci.h |    1 +
>>> >> >> >> >>  9 files changed, 185 insertions(+), 21 deletions(-)
>>> >> >> >> >>
>>> >> >> >> >> diff --git a/drivers/mmc/core/bus.c
>>> b/drivers/mmc/core/bus.c
>>> >> >> >> >> index 5639fdf..83c9f8d 100644
>>> >> >> >> >> --- a/drivers/mmc/core/bus.c
>>> >> >> >> >> +++ b/drivers/mmc/core/bus.c
>>> >> >> >> >> @@ -301,10 +301,11 @@ int mmc_add_card(struct mmc_card
>>> *card)
>>> >> >> >> >>                       mmc_card_ddr_mode(card) ? "DDR " :
>>> "",
>>> >> >> >> >>                       type);
>>> >> >> >> >>       } else {
>>> >> >> >> >> -             printk(KERN_INFO "%s: new %s%s%s card at
>>> address
>>> >> >> >> %04x\n",
>>> >> >> >> >> +             pr_info("%s: new %s%s%s%s card at address
>>> >> %04x\n",
>>> >> >> >> >>                       mmc_hostname(card->host),
>>> >> >> >> >>                       mmc_card_uhs(card) ? "ultra high
>>> speed "
>>> >> :
>>> >> >> >> >>                       (mmc_card_highspeed(card) ? "high
>>> speed
>>> >> " :
>>> >> >> >> ""),
>>> >> >> >> >> +                     (mmc_card_hs200(card) ? "HS200 " :
>>> ""),
>>> >> >> >> >>                       mmc_card_ddr_mode(card) ? "DDR " :
>>> "",
>>> >> >> >> >>                       type, card->rca);
>>> >> >> >> >>       }
>>> >> >> >> >> diff --git a/drivers/mmc/core/mmc.c
>>> b/drivers/mmc/core/mmc.c
>>> >> >> >> >> index a1223bd..f4124d6 100644
>>> >> >> >> >> --- a/drivers/mmc/core/mmc.c
>>> >> >> >> >> +++ b/drivers/mmc/core/mmc.c
>>> >> >> >> >> @@ -285,6 +285,27 @@ static int mmc_read_ext_csd(struct
>>> >> mmc_card
>>> >> >> >> *card,
>>> >> >> >> >> u8 *ext_csd)
>>> >> >> >> >>       }
>>> >> >> >> >>       card->ext_csd.raw_card_type =
>>> >> ext_csd[EXT_CSD_CARD_TYPE];
>>> >> >> >> >>       switch (ext_csd[EXT_CSD_CARD_TYPE] &
>>> >> >> EXT_CSD_CARD_TYPE_MASK) {
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
>>> >> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
>>> >> >> >> >> +             card->ext_csd.card_type =
>>> >> >> EXT_CSD_CARD_TYPE_SDR_200;
>>> >> >> >> >> +             break;
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
>>> >> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
>>> >> >> >> >> +             card->ext_csd.card_type =
>>> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V;
>>> >> >> >> >> +             break;
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
>>> >> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
>>> >> >> >> >> +             card->ext_csd.card_type =
>>> >> >> EXT_CSD_CARD_TYPE_SDR_1_8V;
>>> >> >> >> >> +             break;
>>> >> >> >> >>       case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52
>>> |
>>> >> >> >> >>            EXT_CSD_CARD_TYPE_26:
>>> >> >> >> >>               card->ext_csd.hs_max_dtr = 52000000;
>>> >> >> >> >> @@ -699,6 +720,7 @@ static int mmc_init_card(struct
>>> mmc_host
>>> >> >> *host,
>>> >> >> >> u32
>>> >> >> >> >> ocr,
>>> >> >> >> >>  {
>>> >> >> >> >>       struct mmc_card *card;
>>> >> >> >> >>       int err, ddr = 0;
>>> >> >> >> >> +     int hs_sdr = 0;
>>> >> >> >> >>       u32 cid[4];
>>> >> >> >> >>       unsigned int max_dtr;
>>> >> >> >> >>       u32 rocr;
>>> >> >> >> >> @@ -894,11 +916,16 @@ static int mmc_init_card(struct
>>> mmc_host
>>> >> >> >> *host,
>>> >> >> >> >> u32 ocr,
>>> >> >> >> >>       /*
>>> >> >> >> >>        * Activate high speed (if supported)
>>> >> >> >> >>        */
>>> >> >> >> >> -     if ((card->ext_csd.hs_max_dtr != 0) &&
>>> >> >> >> >> -             (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
>>> >> >> >> >> -             err = mmc_switch(card,
>>> EXT_CSD_CMD_SET_NORMAL,
>>> >> >> >> >> -                              EXT_CSD_HS_TIMING, 1,
>>> >> >> >> >> -                              card-
>>> >> >ext_csd.generic_cmd6_time);
>>> >> >> >> >> +     if (card->ext_csd.hs_max_dtr != 0) {
>>> >> >> >> >> +             err = 0;
>>> >> >> >> >> +             if ((card->ext_csd.hs_max_dtr > 52000000) &&
>>> >> >> >> >> +                 (host->caps2 & MMC_CAP2_HS200))
>>> >> >> >> >> +                     err = mmc_switch(card,
>>> >> >> EXT_CSD_CMD_SET_NORMAL,
>>> >> >> >> >> +                                      EXT_CSD_HS_TIMING,
>>> 2,
>>> >> 0);
>>> >> >> >> >> +             else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
>>> >> >> >> >> +                     err = mmc_switch(card,
>>> >> >> EXT_CSD_CMD_SET_NORMAL,
>>> >> >> >> >> +                                      EXT_CSD_HS_TIMING,
>>> 1,
>>> >> 0);
>>> >> >> >> >> +
>>> >> >> >> >>               if (err && err != -EBADMSG)
>>> >> >> >> >>                       goto free_card;
>>> >> >> >> >>
>>> >> >> >> >> @@ -907,7 +934,11 @@ static int mmc_init_card(struct
>>> mmc_host
>>> >> >> *host,
>>> >> >> >> >> u32 ocr,
>>> >> >> >> >>                              mmc_hostname(card->host));
>>> >> >> >> >>                       err = 0;
>>> >> >> >> >>               } else {
>>> >> >> >> >> -                     mmc_card_set_highspeed(card);
>>> >> >> >> >> +                     if ((card->ext_csd.hs_max_dtr >
>>> >> 52000000)
>>> >> >> &&
>>> >> >> >> >> +                         (host->caps2 & MMC_CAP2_HS200))
>>> >> >> >> >> +                             mmc_card_set_hs200(card);
>>> >> >> >> >> +                     else
>>> >> >> >> >> +                             mmc_card_set_highspeed(card);
>>> >> >> >> >>                       mmc_set_timing(card->host,
>>> >> >> MMC_TIMING_MMC_HS);
>>> >> >> >> >
>>> >> >> >> > MMC_TIMING_MMC_HS200 is defined but still not used.
>>> >> >> >> >
>>> >> >> >> > So I guess it should be like this ::
>>> >> >> >> >  +                      if ((card->ext_csd.hs_max_dtr >
>>> >> 52000000)
>>> >> >> &&
>>> >> >> >> >  +                          (host->caps2 & MMC_CAP2_HS200))
>>> {
>>> >> >> >> >  +                              mmc_card_set_hs200(card);
>>> >> >> >> >  +                      mmc_set_timing(card->host,
>>> >> >> >> MMC_TIMING_MMC_HS200)
>>> >> >> >> >  +                      } else {
>>> >> >> >> >  +
>>>  mmc_card_set_highspeed(card);
>>> >> >> >> >  +                              mmc_set_timing(card->host,
>>> >> >> >> > MMC_TIMING_MMC_HS)
>>> >> >> >> >  +                      }
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >>               }
>>> >> >> >> >>       }
>>> >> >> >> >> @@ -933,7 +964,7 @@ static int mmc_init_card(struct
>>> mmc_host
>>> >> >> *host,
>>> >> >> >> u32
>>> >> >> >> >> ocr,
>>> >> >> >> >>        */
>>> >> >> >> >>       max_dtr = (unsigned int)-1;
>>> >> >> >> >>
>>> >> >> >> >> -     if (mmc_card_highspeed(card)) {
>>> >> >> >> >> +     if (mmc_card_highspeed(card) || mmc_card_hs200(card))
>>> {
>>> >> >> >> >>               if (max_dtr > card->ext_csd.hs_max_dtr)
>>> >> >> >> >>                       max_dtr = card->ext_csd.hs_max_dtr;
>>> >> >> >> >>       } else if (max_dtr > card->csd.max_dtr) {
>>> >> >> >> >> @@ -959,6 +990,18 @@ static int mmc_init_card(struct
>>> mmc_host
>>> >> >> *host,
>>> >> >> >> >> u32 ocr,
>>> >> >> >> >>       }
>>> >> >> >> >>
>>> >> >> >> >>       /*
>>> >> >> >> >> +      * Indicate HS200 SDR mode (if supported).
>>> >> >> >> >> +      */
>>> >> >> >> >> +     if (mmc_card_hs200(card)) {
>>> >> >> >> >> +             if ((card->ext_csd.card_type &
>>> >> >> >> EXT_CSD_CARD_TYPE_SDR_1_8V)
>>> >> >> >> >> +                     && (host->caps2 &
>>> >> MMC_CAP2_HS200_1_8V_SDR))
>>> >> >> >> >> +                             hs_sdr = MMC_1_8V_SDR_MODE;
>>> >> >> >> >> +             else if ((card->ext_csd.card_type &
>>> >> >> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
>>> >> >> >> >> +                     && (host->caps2 &
>>> >> MMC_CAP2_HS200_1_2V_SDR))
>>> >> >> >> >> +                             hs_sdr = MMC_1_2V_SDR_MODE;
>>> >> >> >> >> +     }
>>> >> >> >> >> +
>>> >> >> >> >> +     /*
>>> >> >> >> >>        * Activate wide bus and DDR (if supported).
>>> >> >> >> >>        */
>>> >> >> >> >>       if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
>>> >> >> >> >> @@ -998,6 +1041,17 @@ static int mmc_init_card(struct
>>> mmc_host
>>> >> >> >> *host,
>>> >> >> >> >> u32 ocr,
>>> >> >> >> >>                       if (!err) {
>>> >> >> >> >>                               mmc_set_bus_width(card->host,
>>> >> >> >> bus_width);
>>> >> >> >> >>
>>> >> >> >> >> +                             if ((host->caps2 &
>>> >> MMC_CAP2_HS200)
>>> >> >> &&
>>> >> >> >> >> +                                 card->host->ops-
>>> >> >> >execute_tuning)
>>> >> >> >> >> +                                     err = card->host-
>>> >ops->
>>> >> \
>>> >> >> >> >> +
>>> >> execute_tuning(card-
>>> >> >> >> >host,
>>> >> >> >> >> +
>>> >> >> >> > MMC_SEND_TUNING_BLOCK_HS200);
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> > execute_tuning should be done right after the timing is
>>> changed
>>> >> to
>>> >> >> >> HS200 and
>>> >> >> >> > clock rate is changed to 200Mhz. This is not the correct
>>> >> sequence
>>> >> >> to
>>> >> >> >> call
>>> >> >> >> > the execute_tuning().
>>> >> >> >> > As told earlier, It is mentioned in the spec that tuning
>>> should
>>> >> be
>>> >> >> >> executed after change of buswidth (mandatory). Also it
>>> mentions
>>> >> that
>>> >> >> >> "The host may invoke the HS200 tuning sequence, by sending
>>> CMD21
>>> >> to
>>> >> >> the
>>> >> >> >> device". It means that
>>> >> >> >>  after setting the HS200 mode, Changing to freq > 52Mhz and
>>> >> changing
>>> >> >> >> the bus width tuning can be executed anytime to identify the
>>> >> >> sampling
>>> >> >> >> point to read.(By anytime i mean before actual block read
>>> >> >> Operation).
>>> >> >> >> Can you please point me to the place in the spec where it
>>> >> specifies
>>> >> >> >> tuning should be done immediately after freq change (may be i
>>> >> missed
>>> >> >> >> to read it).
>>> >> >> >
>>> >> >> >
>>> >> >> > Ok. let me ask you this. Why do we run the execute_tuning()?
>>> It's
>>> >> to
>>> >> >> tune
>>> >> >> > the sampling clock generator of host controller before you
>>> start
>>> >> any
>>> >> >> read
>>> >> >> > operation (on command line or data line) from card. If you
>>> don't
>>> >> tune
>>> >> >> the
>>> >> >> > sampling clock generator before the read operation (after
>>> changing
>>> >> >> the
>>> >> >> > timing to HS200 and clock rate to 200mhz), you can't be sure
>>> that
>>> >> >> read
>>> >> >> > operation from card will be completed without errors. You may
>>> get
>>> >> the
>>> >> >> data /
>>> >> >> > cmd response CRC errors. At least this will surely fail on our
>>> MSM
>>> >> >> SDCC host
>>> >> >> > controller. That's what we had faced with SD3.0 UHS-I tuning as
>>> >> well
>>> >> >> as
>>> >> >> > mentioned in http://www.spinics.net/lists/linux-arm-
>>> >> >> msm/msg03867.html.
>>> >> >
>>> >> >> > this tuning is done before any read opration for the best bus
>>> >> width
>>> >> >> supported.
>>> >> > Agreed. But can we be sure that "command response" for bus width
>>> >> change via
>>> >> > CMD6, will not have any command CRC failures if tuning is not
>>> done?
>>> >> All responses are sent on CMD line not on data lines, And sampling
>>> is
>>> >> done for Data lines before reading. So command CRC failure doesnt
>>> >> depend on tuning. If you get error during CMD6 it could be that
>>> device
>>> >> cannot support the bus width at the set frequency.
>>> >
>>> > I guess it's not the correct assumption here. Sampling point tuning
>>> is to
>>> Its Not assumption "Specification says responses are all sent on CMD
>>> only"
>>
>>
>>
>> Where does it say that tuning is not required for data received on command
>> line? If the 200Mhz clock can effect the data received on DATA lines then
>> why it won't affect the data (responses) received on CMD lines?
>> If you still have doubt, I would suggest to get the clarification from
>> JEDEC.  From SD3.01 spec, for sure CMD lines also requires tuning.
>>
>> "Sampling clock generation" on our host controller also says that tuning is
>> required for data transfer on both DATA and CMD lines.
>>
>> I am not sure what is the issue with doing the tuning immediately after
>> changing to bus speed mode to HS200 (changing controller timing, changing
>> clock etc ...)? This is what we are doing it for SD3.0 cards as well.
>>
>> Your current implementation is not going to work with all host controllers.
>>
>>
>>
>>
>>
>>
>>> > tune the sampling point for data received on both CMD and DATA lines
>>> (not
>>> > just data lines). I can't find detailed mentioning of this in eMMC4.5
>>> Pls check the section 6.6.7.1. the 2nd paragraph quotes "which in turn
>>> uses it to find the
>>> optimal sampling point for the data lines"
>>> > (that's the documentation short coming, you can even confirm whether
>>> tuning
>>> > procedure is required for CMD line or not from JEDEC) but SD3.01
>>> > specification does mention this tuning procedure in great details.
>>> NOTE:
>>> > eMMC4.5 HS200 mode is mostly inspired from SD3.01 UHS-I bus speed
>>> modes.
>>> >
>>> > Section " 4.2.4.5 Tuning Command" in "SD3.01 - Simplified
>>> >
>>> (Part_1_Physical_Layer_Simplified_Specification_Ver_3.01_Final_100518)"
>>> > specification(can be downloaded from here:
>>> > https://www.sdcard.org/downloads/pls/), clearly states this:
>>> >
>>> > 4.2.4.5 Tuning Command
>>> > CMD19 is defined for Send Tuning Block Command. R1 type response is
>>> defined.
>>> > CMD19 can be
>>> > executed in transfer state of 1.8V signaling mode while the card is
>>> > unlocked. The other case, CMD19 is
>>> > treated as illegal command. Data block, carried by DAT[3:0], contains
>>> a
>>> > pattern for tuning sampling
>>> > position to receive data on the CMD and DAT[3:0] line. The block
>>> length of
>>> > CMD19 is fixed and CMD16
>>> > is not required.
>>> > I have no idea of the SD spec. I have just seen the eMMC spec and
>>> above quotes might answer your doubt
>>> > So before tuning, you may get the Command CRC errors in HS200 mode.
>>> >
>>> > Regards,
>>> > Subhash
>>> >
>>> >> >
>>> >> >> ps:Chris need your comment on this
>>> >> >> >
>>> >> >> >> >> +
>>> >> >> >> >> +                             if (err) {
>>> >> >> >> >> +                                     pr_warning("tuning
>>> >> >> execution
>>> >> >> >> > failed\n");
>>> >> >> >> >> +                                     continue;
>>> >> >> >> >> +                             }
>>> >> >> >> >> +
>>> >> >> >> >>                               /*
>>> >> >> >> >>                                * If controller can't handle
>>> >> bus
>>> >> >> >> width
>>> >> >> >> > test,
>>> >> >> >> >>                                * compare ext_csd previously
>>> >> read
>>> >> >> in
>>> >> >> >> 1 bit
>>> >> >> >> >> mode
>>> >> >> >> >> @@ -1056,6 +1110,15 @@ static int mmc_init_card(struct
>>> >> mmc_host
>>> >> >> >> *host,
>>> >> >> >> >> u32 ocr,
>>> >> >> >> >>                       mmc_card_set_ddr_mode(card);
>>> >> >> >> >>                       mmc_set_timing(card->host,
>>> >> >> >> MMC_TIMING_UHS_DDR50);
>>> >> >> >> >>                       mmc_set_bus_width(card->host,
>>> >> bus_width);
>>> >> >> >> >> +             } else if (hs_sdr) {
>>> >> >> >> >> +                     if (hs_sdr ==
>>> >> EXT_CSD_CARD_TYPE_SDR_1_2V) {
>>> >> >> >> >> +                             err =
>>> >> mmc_set_signal_voltage(host,
>>> >> >> >> >> +
>>> MMC_SIGNAL_VOLTAGE_120,
>>> >> 0);
>>> >> >> >> >> +                             if (err)
>>> >> >> >> >> +                                     goto err;
>>> >> >> >> >> +                     }
>>> >> >> >> >> +                     mmc_set_timing(card->host,
>>> >> >> MMC_TIMING_MMC_HS);
>>> >> >> >> >> +                     mmc_set_bus_width(card->host,
>>> >> bus_width);
>>> >> >> >> >>               }
>>> >> >> >> >>       }
>>> >> >> >> >>
>>> >> >> >> >> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
>>> >> >> >> >> index 1d5a3bd..c1d3ee3 100644
>>> >> >> >> >> --- a/drivers/mmc/core/sd.c
>>> >> >> >> >> +++ b/drivers/mmc/core/sd.c
>>> >> >> >> >> @@ -660,7 +660,8 @@ static int mmc_sd_init_uhs_card(struct
>>> >> >> mmc_card
>>> >> >> >> >> *card)
>>> >> >> >> >>
>>> >> >> >> >>       /* SPI mode doesn't define CMD19 */
>>> >> >> >> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
>>> >> >> >> >> >execute_tuning)
>>> >> >> >> >> -             err = card->host->ops->execute_tuning(card-
>>> >> >host);
>>> >> >> >> >> +             err = card->host->ops->execute_tuning(card-
>>> >> >host,
>>> >> >> >>   \
>>> >> >> >> >> +
>>> >> >> >> > MMC_SEND_TUNING_BLOCK);
>>> >> >> >> >>
>>> >> >> >> >>  out:
>>> >> >> >> >>       kfree(status);
>>> >> >> >> >> diff --git a/drivers/mmc/core/sdio.c
>>> b/drivers/mmc/core/sdio.c
>>> >> >> >> >> index 8c04f7f..8ef8817 100644
>>> >> >> >> >> --- a/drivers/mmc/core/sdio.c
>>> >> >> >> >> +++ b/drivers/mmc/core/sdio.c
>>> >> >> >> >> @@ -14,6 +14,7 @@
>>> >> >> >> >>
>>> >> >> >> >>  #include <linux/mmc/host.h>
>>> >> >> >> >>  #include <linux/mmc/card.h>
>>> >> >> >> >> +#include <linux/mmc/mmc.h>
>>> >> >> >> >>  #include <linux/mmc/sdio.h>
>>> >> >> >> >>  #include <linux/mmc/sdio_func.h>
>>> >> >> >> >>  #include <linux/mmc/sdio_ids.h>
>>> >> >> >> >> @@ -556,7 +557,8 @@ static int
>>> mmc_sdio_init_uhs_card(struct
>>> >> >> >> mmc_card
>>> >> >> >> >> *card)
>>> >> >> >> >>
>>> >> >> >> >>       /* Initialize and start re-tuning timer */
>>> >> >> >> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
>>> >> >> >> >> >execute_tuning)
>>> >> >> >> >> -             err = card->host->ops->execute_tuning(card-
>>> >> >host);
>>> >> >> >> >> +             err = card->host->ops->execute_tuning(card-
>>> >> >host,
>>> >> >> >> >> +
>>> >> >> >> > MMC_SEND_TUNING_BLOCK);
>>> >> >> >> >>
>>> >> >> >> >>  out:
>>> >> >> >> >>
>>> >> >> >> >> diff --git a/drivers/mmc/host/sdhci.c
>>> >> b/drivers/mmc/host/sdhci.c
>>> >> >> >> >> index a7c2311..13d74bb 100644
>>> >> >> >> >> --- a/drivers/mmc/host/sdhci.c
>>> >> >> >> >> +++ b/drivers/mmc/host/sdhci.c
>>> >> >> >> >> @@ -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
>>> >> >> >> >> @@ -1016,7 +1016,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
>>> >> >> */
>>> >> >> >> >> @@ -1673,7 +1674,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;
>>> >> >> >> >> @@ -1694,10 +1695,13 @@ static int
>>> sdhci_execute_tuning(struct
>>> >> >> >> mmc_host
>>> >> >> >> >> *mmc)
>>> >> >> >> >>        * Host Controller needs tuning only in case of
>>> SDR104
>>> >> mode
>>> >> >> >> >>        * and for SDR50 mode when Use Tuning for SDR50 is
>>> set
>>> >> in
>>> >> >> >> >>        * Capabilities register.
>>> >> >> >> >> +      * If the Host Controller supports the HS200 mode
>>> then
>>> >> >> tuning
>>> >> >> >> >> +      * function has to be executed.
>>> >> >> >> >>        */
>>> >> >> >> >>       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)))
>>> >> >> >> >> +         (host->flags & SDHCI_SDR50_NEEDS_TUNING)) ||
>>> >> >> >> >> +         (host->flags & SDHCI_HS200_NEEDS_TUNING))
>>> >> >> >> >>               ctrl |= SDHCI_CTRL_EXEC_TUNING;
>>> >> >> >> >>       else {
>>> >> >> >> >>               spin_unlock(&host->lock);
>>> >> >> >> >> @@ -1733,7 +1737,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;
>>> >> >> >> >> @@ -1748,7 +1752,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.
>>> >> >> >> >> @@ -2131,12 +2145,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;
>>> >> >> >> >> @@ -2741,6 +2757,10 @@ int sdhci_add_host(struct sdhci_host
>>> >> >> *host)
>>> >> >> >> >>       if (caps[1] & SDHCI_USE_SDR50_TUNING)
>>> >> >> >> >>               host->flags |= SDHCI_SDR50_NEEDS_TUNING;
>>> >> >> >> >>
>>> >> >> >> >> +     /* Does the host needs 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;
>>> >> >> >> >> diff --git a/include/linux/mmc/card.h
>>> >> b/include/linux/mmc/card.h
>>> >> >> >> >> index 534974c..e76f649 100644
>>> >> >> >> >> --- a/include/linux/mmc/card.h
>>> >> >> >> >> +++ b/include/linux/mmc/card.h
>>> >> >> >> >> @@ -209,6 +209,7 @@ struct mmc_card {
>>> >> >> >> >>  #define MMC_STATE_HIGHSPEED_DDR (1<<4)               /*
>>> card
>>> >> is
>>> >> >> in
>>> >> >> >> high
>>> >> >> >> >> speed mode */
>>> >> >> >> >>  #define MMC_STATE_ULTRAHIGHSPEED (1<<5)              /*
>>> card
>>> >> is
>>> >> >> in
>>> >> >> >> ultra
>>> >> >> >> >> high speed mode */
>>> >> >> >> >>  #define MMC_CARD_SDXC                (1<<6)          /*
>>> card
>>> >> is
>>> >> >> >> SDXC */
>>> >> >> >> >> +#define MMC_STATE_HIGHSPEED_200      (1<<7)  /* card is in
>>> >> HS200
>>> >> >> >> >> mode */
>>> >> >> >> >>       unsigned int            quirks;         /* card
>>> quirks
>>> >> */
>>> >> >> >> >>  #define MMC_QUIRK_LENIENT_FN0        (1<<0)          /*
>>> allow
>>> >> >> SDIO
>>> >> >> >> FN0
>>> >> >> >> >> writes outside of the VS CCCR range */
>>> >> >> >> >>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func-
>>> >> >> >> >> >cur_blksize */
>>> >> >> >> >> @@ -365,6 +366,7 @@ static inline void __maybe_unused
>>> >> >> >> >> remove_quirk(struct mmc_card *card, int data)
>>> >> >> >> >>  #define mmc_card_present(c)  ((c)->state &
>>> MMC_STATE_PRESENT)
>>> >> >> >> >>  #define mmc_card_readonly(c) ((c)->state &
>>> >> MMC_STATE_READONLY)
>>> >> >> >> >>  #define mmc_card_highspeed(c)        ((c)->state &
>>> >> >> >> MMC_STATE_HIGHSPEED)
>>> >> >> >> >> +#define mmc_card_hs200(c)    ((c)->state &
>>> >> >> MMC_STATE_HIGHSPEED_200)
>>> >> >> >> >>  #define mmc_card_blockaddr(c)        ((c)->state &
>>> >> >> >> MMC_STATE_BLOCKADDR)
>>> >> >> >> >>  #define mmc_card_ddr_mode(c) ((c)->state &
>>> >> >> MMC_STATE_HIGHSPEED_DDR)
>>> >> >> >> >>  #define mmc_card_uhs(c)              ((c)->state &
>>> >> >> >> >> MMC_STATE_ULTRAHIGHSPEED)
>>> >> >> >> >> @@ -374,6 +376,7 @@ static inline void __maybe_unused
>>> >> >> >> >> remove_quirk(struct mmc_card *card, int data)
>>> >> >> >> >>  #define mmc_card_set_present(c)      ((c)->state |=
>>> >> >> >> MMC_STATE_PRESENT)
>>> >> >> >> >>  #define mmc_card_set_readonly(c) ((c)->state |=
>>> >> >> MMC_STATE_READONLY)
>>> >> >> >> >>  #define mmc_card_set_highspeed(c) ((c)->state |=
>>> >> >> >> MMC_STATE_HIGHSPEED)
>>> >> >> >> >> +#define mmc_card_set_hs200(c)        ((c)->state |=
>>> >> >> >> >> MMC_STATE_HIGHSPEED_200)
>>> >> >> >> >>  #define mmc_card_set_blockaddr(c) ((c)->state |=
>>> >> >> >> MMC_STATE_BLOCKADDR)
>>> >> >> >> >>  #define mmc_card_set_ddr_mode(c) ((c)->state |=
>>> >> >> >> >> MMC_STATE_HIGHSPEED_DDR)
>>> >> >> >> >>  #define mmc_card_set_uhs(c) ((c)->state |=
>>> >> >> >> MMC_STATE_ULTRAHIGHSPEED)
>>> >> >> >> >> diff --git a/include/linux/mmc/host.h
>>> >> b/include/linux/mmc/host.h
>>> >> >> >> >> index 706f722..5eac57a 100644
>>> >> >> >> >> --- a/include/linux/mmc/host.h
>>> >> >> >> >> +++ b/include/linux/mmc/host.h
>>> >> >> >> >> @@ -50,6 +50,7 @@ struct mmc_ios {
>>> >> >> >> >>
>>> >> >> >> >>  #define MMC_TIMING_LEGACY    0
>>> >> >> >> >>  #define MMC_TIMING_MMC_HS    1
>>> >> >> >> >> +#define MMC_TIMING_MMC_HS200 2
>>> >> >> >> >>  #define MMC_TIMING_SD_HS     2
>>> >> >> >> >>  #define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY
>>> >> >> >> >>  #define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS
>>> >> >> >> >> @@ -60,6 +61,8 @@ struct mmc_ios {
>>> >> >> >> >>  #define MMC_SDR_MODE         0
>>> >> >> >> >>  #define MMC_1_2V_DDR_MODE    1
>>> >> >> >> >>  #define MMC_1_8V_DDR_MODE    2
>>> >> >> >> >> +#define MMC_1_2V_SDR_MODE    3
>>> >> >> >> >> +#define MMC_1_8V_SDR_MODE    4
>>> >> >> >> >>
>>> >> >> >> >>       unsigned char   signal_voltage;         /* signalling
>>> >> >> voltage
>>> >> >> >> >> (1.8V or 3.3V) */
>>> >> >> >> >>
>>> >> >> >> >> @@ -148,7 +151,9 @@ struct mmc_host_ops {
>>> >> >> >> >>       void    (*init_card)(struct mmc_host *host, struct
>>> >> mmc_card
>>> >> >> >> *card);
>>> >> >> >> >>
>>> >> >> >> >>       int     (*start_signal_voltage_switch)(struct
>>> mmc_host
>>> >> >> *host,
>>> >> >> >> >> struct mmc_ios *ios);
>>> >> >> >> >> -     int     (*execute_tuning)(struct mmc_host *host);
>>> >> >> >> >> +
>>> >> >> >> >> +     /* The tuning command opcode value is different for
>>> SD
>>> >> and
>>> >> >> >> eMMC
>>> >> >> >> >> cards */
>>> >> >> >> >> +     int     (*execute_tuning)(struct mmc_host *host, u32
>>> >> >> opcode);
>>> >> >> >> >>       void    (*enable_preset_value)(struct mmc_host *host,
>>> >> bool
>>> >> >> >> enable);
>>> >> >> >> >>       int     (*select_drive_strength)(unsigned int
>>> max_dtr,
>>> >> int
>>> >> >> >> >> host_drv, int card_drv);
>>> >> >> >> >>       void    (*hw_reset)(struct mmc_host *host);
>>> >> >> >> >> @@ -242,6 +247,10 @@ struct mmc_host {
>>> >> >> >> >>  #define MMC_CAP2_CACHE_CTRL  (1 << 1)        /* Allow
>>> cache
>>> >> >> control
>>> >> >> >> */
>>> >> >> >> >>  #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)    /* Notify
>>> >> poweroff
>>> >> >> >> >> supported */
>>> >> >> >> >>  #define MMC_CAP2_NO_MULTI_READ       (1 << 3)        /*
>>> >> >> Multiblock
>>> >> >> >> reads
>>> >> >> >> >> don't work */
>>> >> >> >> >> +#define MMC_CAP2_HS200_1_8V_SDR      (1 << 4)        /*
>>> can
>>> >> >> support
>>> >> >> >> */
>>> >> >> >> >> +#define MMC_CAP2_HS200_1_2V_SDR      (1 << 5)        /*
>>> can
>>> >> >> support
>>> >> >> >> */
>>> >> >> >> >> +#define MMC_CAP2_HS200
>>> (MMC_CAP2_HS200_1_8V_SDR
>>> >> |
>>> >> >> \
>>> >> >> >> >> +                              MMC_CAP2_HS200_1_2V_SDR)
>>> >> >> >> >>
>>> >> >> >> >>       mmc_pm_flag_t           pm_caps;        /* supported
>>> pm
>>> >> >> >> features */
>>> >> >> >> >>       unsigned int        power_notify_type;
>>> >> >> >> >> diff --git a/include/linux/mmc/mmc.h
>>> b/include/linux/mmc/mmc.h
>>> >> >> >> >> index 0e71356..7996272 100644
>>> >> >> >> >> --- a/include/linux/mmc/mmc.h
>>> >> >> >> >> +++ b/include/linux/mmc/mmc.h
>>> >> >> >> >> @@ -51,6 +51,7 @@
>>> >> >> >> >>  #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data
>>> >> addr
>>> >> >> R1
>>> >> >> >> >> */
>>> >> >> >> >>  #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data
>>> >> addr
>>> >> >> R1
>>> >> >> >> >> */
>>> >> >> >> >>  #define MMC_SEND_TUNING_BLOCK    19   /* adtc
>>> >> >>  R1
>>> >> >> >> >> */
>>> >> >> >> >> +#define MMC_SEND_TUNING_BLOCK_HS200  21      /* adtc R1
>>>  */
>>> >> >> >> >>
>>> >> >> >> >>    /* class 3 */
>>> >> >> >> >>  #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data
>>> >> addr
>>> >> >> R1
>>> >> >> >> >> */
>>> >> >> >> >> @@ -333,13 +334,76 @@ struct _mmc_csd {
>>> >> >> >> >>
>>> >> >> >> >>  #define EXT_CSD_CARD_TYPE_26 (1<<0)  /* Card can run at
>>> 26MHz
>>> >> */
>>> >> >> >> >>  #define EXT_CSD_CARD_TYPE_52 (1<<1)  /* Card can run at
>>> 52MHz
>>> >> */
>>> >> >> >> >> -#define EXT_CSD_CARD_TYPE_MASK       0xF     /* Mask out
>>> >> >> reserved
>>> >> >> >> bits */
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_MASK       0x3F    /* Mask out
>>> >> >> reserved
>>> >> >> >> bits */
>>> >> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can
>>> run
>>> >> at
>>> >> >> >> 52MHz
>>> >> >> >> >> */
>>> >> >> >> >>                                            /* DDR mode
>>> @1.8V
>>> >> or
>>> >> >> 3V
>>> >> >> >> I/O */
>>> >> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can
>>> run
>>> >> at
>>> >> >> >> 52MHz
>>> >> >> >> >> */
>>> >> >> >> >>                                            /* DDR mode
>>> @1.2V
>>> >> I/O
>>> >> >> */
>>> >> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_52
>>> >> >> (EXT_CSD_CARD_TYPE_DDR_1_8V
>>> >> >> >>  \
>>> >> >> >> >>                                       |
>>> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V)
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V   (1<<4)  /* Card can
>>> run
>>> >> at
>>> >> >> >> >> 200MHz */
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V   (1<<5)  /* Card can
>>> run
>>> >> at
>>> >> >> >> >> 200MHz */
>>> >> >> >> >> +                                             /* SDR mode
>>> >> @1.2V
>>> >> >> I/O
>>> >> >> >> */
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_200
>>> >>  (EXT_CSD_CARD_TYPE_SDR_1_8V
>>> >> >> >>   \
>>> >> >> >> >> +                                     |
>>> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL
>>> >>  (EXT_CSD_CARD_TYPE_SDR_200
>>> >> >> >>  \
>>> >> >> >> >> +                                     |
>>> EXT_CSD_CARD_TYPE_52
>>> >> >> >>  \
>>> >> >> >> >> +                                     |
>>> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_2V_ALL
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V     \
>>> >> >> >> >> +                                     |
>>> EXT_CSD_CARD_TYPE_52
>>> >> >> >>  \
>>> >> >> >> >> +                                     |
>>> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_8V_ALL
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V     \
>>> >> >> >> >> +                                     |
>>> EXT_CSD_CARD_TYPE_52
>>> >> >> >>  \
>>> >> >> >> >> +                                     |
>>> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52
>>> >> >> >> (EXT_CSD_CARD_TYPE_SDR_200
>>> >> >> >> >> \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >>
>>> >> >> >> >>  #define EXT_CSD_BUS_WIDTH_1  0       /* Card is in 1 bit
>>> mode
>>> >> */
>>> >> >> >> >>  #define EXT_CSD_BUS_WIDTH_4  1       /* Card is in 4 bit
>>> mode
>>> >> */
>>> >> >> >> >> diff --git a/include/linux/mmc/sdhci.h
>>> >> >> b/include/linux/mmc/sdhci.h
>>> >> >> >> >> index e4b6935..d9a2222 100644
>>> >> >> >> >> --- a/include/linux/mmc/sdhci.h
>>> >> >> >> >> +++ b/include/linux/mmc/sdhci.h
>>> >> >> >> >> @@ -121,6 +121,7 @@ struct sdhci_host {
>>> >> >> >> >>  #define SDHCI_AUTO_CMD23     (1<<7)  /* Auto CMD23 support
>>> */
>>> >> >> >> >>  #define SDHCI_PV_ENABLED     (1<<8)  /* Preset value
>>> enabled
>>> >> */
>>> >> >> >> >>  #define SDHCI_SDIO_IRQ_ENABLED       (1<<9)  /* SDIO irq
>>> >> enabled
>>> >> >> */
>>> >> >> >> >> +#define SDHCI_HS200_NEEDS_TUNING (1<<10)     /* HS200
>>> needs
>>> >> >> tuning
>>> >> >> >> */
>>> >> >> >> >>
>>> >> >> >> >>       unsigned int version;   /* SDHCI spec. version */
>>> >> >> >> >>
>>> >> >> >> >> --
>>> >> >> >> >> 1.7.1
>>> >> >> >> >>
>>> >> >> >> >> --
>>> >> >> >> >> To unsubscribe from this list: send the line "unsubscribe
>>> >> linux-
>>> >> >> mmc"
>>> >> >> >> in
>>> >> >> >> >> the body of a message to majordomo@vger.kernel.org
>>> >> >> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
>>> >> >> info.html
>>> >> >> >> >
>>> >> >> >> > --
>>> >> >> >> > To unsubscribe from this list: send the line "unsubscribe
>>> >> linux-
>>> >> >> mmc"
>>> >> >> >> in
>>> >> >> >> > the body of a message to majordomo@vger.kernel.org
>>> >> >> >> > More majordomo info at  http://vger.kernel.org/majordomo-
>>> >> info.html
>>> >> >> >> >
>>> >> >> >> --
>>> >> >> >> To unsubscribe from this list: send the line "unsubscribe
>>> linux-
>>> >> mmc"
>>> >> >> in
>>> >> >> >> the body of a message to majordomo@vger.kernel.org
>>> >> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
>>> >> info.html
>>> >> >> >
>>> >> >> --
>>> >> >> To unsubscribe from this list: send the line "unsubscribe linux-
>>> mmc"
>>> >> in
>>> >> >> the body of a message to majordomo@vger.kernel.org
>>> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
>>> info.html
>>> >> >
>>> >
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Girish K S Dec. 12, 2011, 6:50 a.m. UTC | #12
On 5 December 2011 20:29, Saugata Das <saugata.das@linaro.org> wrote:
> Hi Girish
>
> Please refer to Figure 71 (HS200 device output timing) of the MMC-4.5
> spec. It shows that both CMD and DATA[7-0] will have some latency till
> valid window. This implies that even the CMD line will need tuning for
> reading the response. The specification talks about identifying
> sampling point for data lines by reading tuning blocks. Based on host
> controller capability, even the CMD line will get the good sample
> point during the same tuning sequence.
>
> We need to have the tuning done (execute_tuning) soon after switching
> to HS200 mode and 200MHz clock.
>
If i make a change as per subhash suggestion"set bus width before
setting the HS200 mode." then it will affect the entire frame work of
mmc which is developed as per Annexure A6.1 A.6.2 A.6.3 (mentions the
steps for bus initialization). can any of you suggest a way to do
this.
>
> Regards
> Saugata
>
>
> On 5 December 2011 16:59, Subhash Jadavani <subhashj@codeaurora.org> wrote:
>>
>>
>>> -----Original Message-----
>>> From: Girish K S [mailto:girish.shivananjappa@linaro.org]
>>> Sent: Monday, December 05, 2011 12:20 PM
>>> To: Subhash Jadavani
>>> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>>> soc@vger.kernel.org; Chris Ball
>>> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>>>
>>> On 5 December 2011 11:46, Subhash Jadavani <subhashj@codeaurora.org>
>>> wrote:
>>> >
>>> >
>>> >> -----Original Message-----
>>> >> From: Girish K S [mailto:girish.shivananjappa@linaro.org]
>>> >> Sent: Friday, December 02, 2011 5:08 PM
>>> >> To: Subhash Jadavani
>>> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>>> >> soc@vger.kernel.org; Chris Ball
>>> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>>> >>
>>> >> On 2 December 2011 00:02, Subhash Jadavani <subhashj@codeaurora.org>
>>> >> wrote:
>>> >> >
>>> >> >
>>> >> >> -----Original Message-----
>>> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>>> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
>>> >> >> Sent: Thursday, December 01, 2011 7:48 PM
>>> >> >> To: Subhash Jadavani
>>> >> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>>> >> >> soc@vger.kernel.org; Chris Ball
>>> >> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC
>>> 4.5
>>> >> >>
>>> >> >> On 1 December 2011 16:27, Subhash Jadavani
>>> <subhashj@codeaurora.org>
>>> >> >> wrote:
>>> >> >> >
>>> >> >> >
>>> >> >> >> -----Original Message-----
>>> >> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>>> >> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
>>> >> >> >> Sent: Thursday, December 01, 2011 3:58 PM
>>> >> >> >> To: Subhash Jadavani
>>> >> >> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-
>>> samsung-
>>> >> >> >> soc@vger.kernel.org; Chris Ball
>>> >> >> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC
>>> >> 4.5
>>> >> >> >>
>>> >> >> >> On 1 December 2011 15:33, Subhash Jadavani
>>> >> <subhashj@codeaurora.org>
>>> >> >> >> wrote:
>>> >> >> >> > Hi Girish,
>>> >> >> >> >
>>> >> >> >> >> -----Original Message-----
>>> >> >> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>>> >> >> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
>>> >> >> >> >> Sent: Wednesday, November 30, 2011 2:24 PM
>>> >> >> >> >> To: linux-mmc@vger.kernel.org
>>> >> >> >> >> Cc: patches@linaro.org; linux-samsung-soc@vger.kernel.org;
>>> >> >> >> >> subhashj@codeaurora.org; Girish K S; Chris Ball
>>> >> >> >> >> Subject: [PATCH V5] mmc: core: HS200 mode support for eMMC
>>> 4.5
>>> >> >> >> >>
>>> >> >> >> >> This patch adds the support of the HS200 bus speed for eMMC
>>> >> 4.5
>>> >> >> >> >> devices.
>>> >> >> >> >> The eMMC 4.5 devices have support for 200MHz bus speed.The
>>> mmc
>>> >> >> core
>>> >> >> >> and
>>> >> >> >> >> host modules have been touched to add support for this
>>> module.
>>> >> >> >> >>
>>> >> >> >> >> It is necessary to know the card type in the sdhci.c file
>>> to
>>> >> add
>>> >> >> >> >> support
>>> >> >> >> >> for eMMC tuning function. So card.h file is included to
>>> import
>>> >> >> the
>>> >> >> >> card
>>> >> >> >> >> data structure.
>>> >> >> >> >>
>>> >> >> >> >> cc: Chris Ball <cjb@laptop.org>
>>> >> >> >> >> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
>>> >> >> >> >> ---
>>> >> >> >> >> Changes in v5:
>>> >> >> >> >>       Reduced the case statements for better code
>>> readability.
>>> >> >> >> Removed
>>> >> >> >> >>       unused macro definitions. Modified the tuning
>>> function
>>> >> >> >> prototype
>>> >> >> >> >>       and definition to support tuning for both SD and eMMC
>>> >> >> cards.
>>> >> >> >> >> Changes in v4:
>>> >> >> >> >>       Rebased onto chris-mmc/mmc-next branch. This patch is
>>> >> >> >> >> successfully
>>> >> >> >> >>       applied on commit with id
>>> >> >> >> >> de022ed3fdc14808299b2fa66dbb1ed5ab921912.
>>> >> >> >> >> Changes in v3:
>>> >> >> >> >>       In the previous commits of chris-mmc/mmc-next branch,
>>> >> the
>>> >> >> >> patch
>>> >> >> >> >> with
>>> >> >> >> >>       commit id (c0f22a2c92e357e7cb3988b0b13034d70b7461f9)
>>> >> >> defines
>>> >> >> >> >> caps2 for
>>> >> >> >> >>       more capabilities. This patch version deletes the
>>> member
>>> >> >> >> >> ext_caps(created
>>> >> >> >> >>       in my earlier patch) from struct mmc_host and reuses
>>> >> >> already
>>> >> >> >> >> accepted
>>> >> >> >> >>       caps2 member.
>>> >> >> >> >> Changes in v2:
>>> >> >> >> >>       Rebased to latest chris-mmc/mmc-next branch. Resolved
>>> >> >> >> indentation
>>> >> >> >> >>       problems identified in review. This patch has to be
>>> >> applied
>>> >> >> >> >> before
>>> >> >> >> >>       the patch released for modifying the printk messages.
>>> >> >> >> >> Changes in v1:
>>> >> >> >> >>       Case statements in switch that produce same result
>>> have
>>> >> >> >> >>       been combined to reduce repeated assignments.
>>> >> >> >> >>       patch recreated after rebase to chris balls mmc-next
>>> >> >> branch.
>>> >> >> >> >>
>>> >> >> >> >>  drivers/mmc/core/bus.c    |    3 +-
>>> >> >> >> >>  drivers/mmc/core/mmc.c    |   77
>>> >> >> >> >> ++++++++++++++++++++++++++++++++++++++++----
>>> >> >> >> >>  drivers/mmc/core/sd.c     |    3 +-
>>> >> >> >> >>  drivers/mmc/core/sdio.c   |    4 ++-
>>> >> >> >> >>  drivers/mmc/host/sdhci.c  |   38 +++++++++++++++++-----
>>> >> >> >> >>  include/linux/mmc/card.h  |    3 ++
>>> >> >> >> >>  include/linux/mmc/host.h  |   11 ++++++-
>>> >> >> >> >>  include/linux/mmc/mmc.h   |   66
>>> >> >> >> >> ++++++++++++++++++++++++++++++++++++++-
>>> >> >> >> >>  include/linux/mmc/sdhci.h |    1 +
>>> >> >> >> >>  9 files changed, 185 insertions(+), 21 deletions(-)
>>> >> >> >> >>
>>> >> >> >> >> diff --git a/drivers/mmc/core/bus.c
>>> b/drivers/mmc/core/bus.c
>>> >> >> >> >> index 5639fdf..83c9f8d 100644
>>> >> >> >> >> --- a/drivers/mmc/core/bus.c
>>> >> >> >> >> +++ b/drivers/mmc/core/bus.c
>>> >> >> >> >> @@ -301,10 +301,11 @@ int mmc_add_card(struct mmc_card
>>> *card)
>>> >> >> >> >>                       mmc_card_ddr_mode(card) ? "DDR " :
>>> "",
>>> >> >> >> >>                       type);
>>> >> >> >> >>       } else {
>>> >> >> >> >> -             printk(KERN_INFO "%s: new %s%s%s card at
>>> address
>>> >> >> >> %04x\n",
>>> >> >> >> >> +             pr_info("%s: new %s%s%s%s card at address
>>> >> %04x\n",
>>> >> >> >> >>                       mmc_hostname(card->host),
>>> >> >> >> >>                       mmc_card_uhs(card) ? "ultra high
>>> speed "
>>> >> :
>>> >> >> >> >>                       (mmc_card_highspeed(card) ? "high
>>> speed
>>> >> " :
>>> >> >> >> ""),
>>> >> >> >> >> +                     (mmc_card_hs200(card) ? "HS200 " :
>>> ""),
>>> >> >> >> >>                       mmc_card_ddr_mode(card) ? "DDR " :
>>> "",
>>> >> >> >> >>                       type, card->rca);
>>> >> >> >> >>       }
>>> >> >> >> >> diff --git a/drivers/mmc/core/mmc.c
>>> b/drivers/mmc/core/mmc.c
>>> >> >> >> >> index a1223bd..f4124d6 100644
>>> >> >> >> >> --- a/drivers/mmc/core/mmc.c
>>> >> >> >> >> +++ b/drivers/mmc/core/mmc.c
>>> >> >> >> >> @@ -285,6 +285,27 @@ static int mmc_read_ext_csd(struct
>>> >> mmc_card
>>> >> >> >> *card,
>>> >> >> >> >> u8 *ext_csd)
>>> >> >> >> >>       }
>>> >> >> >> >>       card->ext_csd.raw_card_type =
>>> >> ext_csd[EXT_CSD_CARD_TYPE];
>>> >> >> >> >>       switch (ext_csd[EXT_CSD_CARD_TYPE] &
>>> >> >> EXT_CSD_CARD_TYPE_MASK) {
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
>>> >> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
>>> >> >> >> >> +             card->ext_csd.card_type =
>>> >> >> EXT_CSD_CARD_TYPE_SDR_200;
>>> >> >> >> >> +             break;
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
>>> >> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
>>> >> >> >> >> +             card->ext_csd.card_type =
>>> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V;
>>> >> >> >> >> +             break;
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
>>> >> >> >> >> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
>>> >> >> >> >> +             card->ext_csd.hs_max_dtr = 200000000;
>>> >> >> >> >> +             card->ext_csd.card_type =
>>> >> >> EXT_CSD_CARD_TYPE_SDR_1_8V;
>>> >> >> >> >> +             break;
>>> >> >> >> >>       case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52
>>> |
>>> >> >> >> >>            EXT_CSD_CARD_TYPE_26:
>>> >> >> >> >>               card->ext_csd.hs_max_dtr = 52000000;
>>> >> >> >> >> @@ -699,6 +720,7 @@ static int mmc_init_card(struct
>>> mmc_host
>>> >> >> *host,
>>> >> >> >> u32
>>> >> >> >> >> ocr,
>>> >> >> >> >>  {
>>> >> >> >> >>       struct mmc_card *card;
>>> >> >> >> >>       int err, ddr = 0;
>>> >> >> >> >> +     int hs_sdr = 0;
>>> >> >> >> >>       u32 cid[4];
>>> >> >> >> >>       unsigned int max_dtr;
>>> >> >> >> >>       u32 rocr;
>>> >> >> >> >> @@ -894,11 +916,16 @@ static int mmc_init_card(struct
>>> mmc_host
>>> >> >> >> *host,
>>> >> >> >> >> u32 ocr,
>>> >> >> >> >>       /*
>>> >> >> >> >>        * Activate high speed (if supported)
>>> >> >> >> >>        */
>>> >> >> >> >> -     if ((card->ext_csd.hs_max_dtr != 0) &&
>>> >> >> >> >> -             (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
>>> >> >> >> >> -             err = mmc_switch(card,
>>> EXT_CSD_CMD_SET_NORMAL,
>>> >> >> >> >> -                              EXT_CSD_HS_TIMING, 1,
>>> >> >> >> >> -                              card-
>>> >> >ext_csd.generic_cmd6_time);
>>> >> >> >> >> +     if (card->ext_csd.hs_max_dtr != 0) {
>>> >> >> >> >> +             err = 0;
>>> >> >> >> >> +             if ((card->ext_csd.hs_max_dtr > 52000000) &&
>>> >> >> >> >> +                 (host->caps2 & MMC_CAP2_HS200))
>>> >> >> >> >> +                     err = mmc_switch(card,
>>> >> >> EXT_CSD_CMD_SET_NORMAL,
>>> >> >> >> >> +                                      EXT_CSD_HS_TIMING,
>>> 2,
>>> >> 0);
>>> >> >> >> >> +             else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
>>> >> >> >> >> +                     err = mmc_switch(card,
>>> >> >> EXT_CSD_CMD_SET_NORMAL,
>>> >> >> >> >> +                                      EXT_CSD_HS_TIMING,
>>> 1,
>>> >> 0);
>>> >> >> >> >> +
>>> >> >> >> >>               if (err && err != -EBADMSG)
>>> >> >> >> >>                       goto free_card;
>>> >> >> >> >>
>>> >> >> >> >> @@ -907,7 +934,11 @@ static int mmc_init_card(struct
>>> mmc_host
>>> >> >> *host,
>>> >> >> >> >> u32 ocr,
>>> >> >> >> >>                              mmc_hostname(card->host));
>>> >> >> >> >>                       err = 0;
>>> >> >> >> >>               } else {
>>> >> >> >> >> -                     mmc_card_set_highspeed(card);
>>> >> >> >> >> +                     if ((card->ext_csd.hs_max_dtr >
>>> >> 52000000)
>>> >> >> &&
>>> >> >> >> >> +                         (host->caps2 & MMC_CAP2_HS200))
>>> >> >> >> >> +                             mmc_card_set_hs200(card);
>>> >> >> >> >> +                     else
>>> >> >> >> >> +                             mmc_card_set_highspeed(card);
>>> >> >> >> >>                       mmc_set_timing(card->host,
>>> >> >> MMC_TIMING_MMC_HS);
>>> >> >> >> >
>>> >> >> >> > MMC_TIMING_MMC_HS200 is defined but still not used.
>>> >> >> >> >
>>> >> >> >> > So I guess it should be like this ::
>>> >> >> >> >  +                      if ((card->ext_csd.hs_max_dtr >
>>> >> 52000000)
>>> >> >> &&
>>> >> >> >> >  +                          (host->caps2 & MMC_CAP2_HS200))
>>> {
>>> >> >> >> >  +                              mmc_card_set_hs200(card);
>>> >> >> >> >  +                      mmc_set_timing(card->host,
>>> >> >> >> MMC_TIMING_MMC_HS200)
>>> >> >> >> >  +                      } else {
>>> >> >> >> >  +
>>>  mmc_card_set_highspeed(card);
>>> >> >> >> >  +                              mmc_set_timing(card->host,
>>> >> >> >> > MMC_TIMING_MMC_HS)
>>> >> >> >> >  +                      }
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> >>               }
>>> >> >> >> >>       }
>>> >> >> >> >> @@ -933,7 +964,7 @@ static int mmc_init_card(struct
>>> mmc_host
>>> >> >> *host,
>>> >> >> >> u32
>>> >> >> >> >> ocr,
>>> >> >> >> >>        */
>>> >> >> >> >>       max_dtr = (unsigned int)-1;
>>> >> >> >> >>
>>> >> >> >> >> -     if (mmc_card_highspeed(card)) {
>>> >> >> >> >> +     if (mmc_card_highspeed(card) || mmc_card_hs200(card))
>>> {
>>> >> >> >> >>               if (max_dtr > card->ext_csd.hs_max_dtr)
>>> >> >> >> >>                       max_dtr = card->ext_csd.hs_max_dtr;
>>> >> >> >> >>       } else if (max_dtr > card->csd.max_dtr) {
>>> >> >> >> >> @@ -959,6 +990,18 @@ static int mmc_init_card(struct
>>> mmc_host
>>> >> >> *host,
>>> >> >> >> >> u32 ocr,
>>> >> >> >> >>       }
>>> >> >> >> >>
>>> >> >> >> >>       /*
>>> >> >> >> >> +      * Indicate HS200 SDR mode (if supported).
>>> >> >> >> >> +      */
>>> >> >> >> >> +     if (mmc_card_hs200(card)) {
>>> >> >> >> >> +             if ((card->ext_csd.card_type &
>>> >> >> >> EXT_CSD_CARD_TYPE_SDR_1_8V)
>>> >> >> >> >> +                     && (host->caps2 &
>>> >> MMC_CAP2_HS200_1_8V_SDR))
>>> >> >> >> >> +                             hs_sdr = MMC_1_8V_SDR_MODE;
>>> >> >> >> >> +             else if ((card->ext_csd.card_type &
>>> >> >> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
>>> >> >> >> >> +                     && (host->caps2 &
>>> >> MMC_CAP2_HS200_1_2V_SDR))
>>> >> >> >> >> +                             hs_sdr = MMC_1_2V_SDR_MODE;
>>> >> >> >> >> +     }
>>> >> >> >> >> +
>>> >> >> >> >> +     /*
>>> >> >> >> >>        * Activate wide bus and DDR (if supported).
>>> >> >> >> >>        */
>>> >> >> >> >>       if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
>>> >> >> >> >> @@ -998,6 +1041,17 @@ static int mmc_init_card(struct
>>> mmc_host
>>> >> >> >> *host,
>>> >> >> >> >> u32 ocr,
>>> >> >> >> >>                       if (!err) {
>>> >> >> >> >>                               mmc_set_bus_width(card->host,
>>> >> >> >> bus_width);
>>> >> >> >> >>
>>> >> >> >> >> +                             if ((host->caps2 &
>>> >> MMC_CAP2_HS200)
>>> >> >> &&
>>> >> >> >> >> +                                 card->host->ops-
>>> >> >> >execute_tuning)
>>> >> >> >> >> +                                     err = card->host-
>>> >ops->
>>> >> \
>>> >> >> >> >> +
>>> >> execute_tuning(card-
>>> >> >> >> >host,
>>> >> >> >> >> +
>>> >> >> >> > MMC_SEND_TUNING_BLOCK_HS200);
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >> > execute_tuning should be done right after the timing is
>>> changed
>>> >> to
>>> >> >> >> HS200 and
>>> >> >> >> > clock rate is changed to 200Mhz. This is not the correct
>>> >> sequence
>>> >> >> to
>>> >> >> >> call
>>> >> >> >> > the execute_tuning().
>>> >> >> >> > As told earlier, It is mentioned in the spec that tuning
>>> should
>>> >> be
>>> >> >> >> executed after change of buswidth (mandatory). Also it
>>> mentions
>>> >> that
>>> >> >> >> "The host may invoke the HS200 tuning sequence, by sending
>>> CMD21
>>> >> to
>>> >> >> the
>>> >> >> >> device". It means that
>>> >> >> >>  after setting the HS200 mode, Changing to freq > 52Mhz and
>>> >> changing
>>> >> >> >> the bus width tuning can be executed anytime to identify the
>>> >> >> sampling
>>> >> >> >> point to read.(By anytime i mean before actual block read
>>> >> >> Operation).
>>> >> >> >> Can you please point me to the place in the spec where it
>>> >> specifies
>>> >> >> >> tuning should be done immediately after freq change (may be i
>>> >> missed
>>> >> >> >> to read it).
>>> >> >> >
>>> >> >> >
>>> >> >> > Ok. let me ask you this. Why do we run the execute_tuning()?
>>> It's
>>> >> to
>>> >> >> tune
>>> >> >> > the sampling clock generator of host controller before you
>>> start
>>> >> any
>>> >> >> read
>>> >> >> > operation (on command line or data line) from card. If you
>>> don't
>>> >> tune
>>> >> >> the
>>> >> >> > sampling clock generator before the read operation (after
>>> changing
>>> >> >> the
>>> >> >> > timing to HS200 and clock rate to 200mhz), you can't be sure
>>> that
>>> >> >> read
>>> >> >> > operation from card will be completed without errors. You may
>>> get
>>> >> the
>>> >> >> data /
>>> >> >> > cmd response CRC errors. At least this will surely fail on our
>>> MSM
>>> >> >> SDCC host
>>> >> >> > controller. That's what we had faced with SD3.0 UHS-I tuning as
>>> >> well
>>> >> >> as
>>> >> >> > mentioned in http://www.spinics.net/lists/linux-arm-
>>> >> >> msm/msg03867.html.
>>> >> >
>>> >> >> > this tuning is done before any read opration for the best bus
>>> >> width
>>> >> >> supported.
>>> >> > Agreed. But can we be sure that "command response" for bus width
>>> >> change via
>>> >> > CMD6, will not have any command CRC failures if tuning is not
>>> done?
>>> >> All responses are sent on CMD line not on data lines, And sampling
>>> is
>>> >> done for Data lines before reading. So command CRC failure doesnt
>>> >> depend on tuning. If you get error during CMD6 it could be that
>>> device
>>> >> cannot support the bus width at the set frequency.
>>> >
>>> > I guess it's not the correct assumption here. Sampling point tuning
>>> is to
>>> Its Not assumption "Specification says responses are all sent on CMD
>>> only"
>>
>>
>>
>> Where does it say that tuning is not required for data received on command
>> line? If the 200Mhz clock can effect the data received on DATA lines then
>> why it won't affect the data (responses) received on CMD lines?
>> If you still have doubt, I would suggest to get the clarification from
>> JEDEC.  From SD3.01 spec, for sure CMD lines also requires tuning.
>>
>> "Sampling clock generation" on our host controller also says that tuning is
>> required for data transfer on both DATA and CMD lines.
>>
>> I am not sure what is the issue with doing the tuning immediately after
>> changing to bus speed mode to HS200 (changing controller timing, changing
>> clock etc ...)? This is what we are doing it for SD3.0 cards as well.
>>
>> Your current implementation is not going to work with all host controllers.
>>
>>
>>
>>
>>
>>
>>> > tune the sampling point for data received on both CMD and DATA lines
>>> (not
>>> > just data lines). I can't find detailed mentioning of this in eMMC4.5
>>> Pls check the section 6.6.7.1. the 2nd paragraph quotes "which in turn
>>> uses it to find the
>>> optimal sampling point for the data lines"
>>> > (that's the documentation short coming, you can even confirm whether
>>> tuning
>>> > procedure is required for CMD line or not from JEDEC) but SD3.01
>>> > specification does mention this tuning procedure in great details.
>>> NOTE:
>>> > eMMC4.5 HS200 mode is mostly inspired from SD3.01 UHS-I bus speed
>>> modes.
>>> >
>>> > Section " 4.2.4.5 Tuning Command" in "SD3.01 - Simplified
>>> >
>>> (Part_1_Physical_Layer_Simplified_Specification_Ver_3.01_Final_100518)"
>>> > specification(can be downloaded from here:
>>> > https://www.sdcard.org/downloads/pls/), clearly states this:
>>> >
>>> > 4.2.4.5 Tuning Command
>>> > CMD19 is defined for Send Tuning Block Command. R1 type response is
>>> defined.
>>> > CMD19 can be
>>> > executed in transfer state of 1.8V signaling mode while the card is
>>> > unlocked. The other case, CMD19 is
>>> > treated as illegal command. Data block, carried by DAT[3:0], contains
>>> a
>>> > pattern for tuning sampling
>>> > position to receive data on the CMD and DAT[3:0] line. The block
>>> length of
>>> > CMD19 is fixed and CMD16
>>> > is not required.
>>> > I have no idea of the SD spec. I have just seen the eMMC spec and
>>> above quotes might answer your doubt
>>> > So before tuning, you may get the Command CRC errors in HS200 mode.
>>> >
>>> > Regards,
>>> > Subhash
>>> >
>>> >> >
>>> >> >> ps:Chris need your comment on this
>>> >> >> >
>>> >> >> >> >> +
>>> >> >> >> >> +                             if (err) {
>>> >> >> >> >> +                                     pr_warning("tuning
>>> >> >> execution
>>> >> >> >> > failed\n");
>>> >> >> >> >> +                                     continue;
>>> >> >> >> >> +                             }
>>> >> >> >> >> +
>>> >> >> >> >>                               /*
>>> >> >> >> >>                                * If controller can't handle
>>> >> bus
>>> >> >> >> width
>>> >> >> >> > test,
>>> >> >> >> >>                                * compare ext_csd previously
>>> >> read
>>> >> >> in
>>> >> >> >> 1 bit
>>> >> >> >> >> mode
>>> >> >> >> >> @@ -1056,6 +1110,15 @@ static int mmc_init_card(struct
>>> >> mmc_host
>>> >> >> >> *host,
>>> >> >> >> >> u32 ocr,
>>> >> >> >> >>                       mmc_card_set_ddr_mode(card);
>>> >> >> >> >>                       mmc_set_timing(card->host,
>>> >> >> >> MMC_TIMING_UHS_DDR50);
>>> >> >> >> >>                       mmc_set_bus_width(card->host,
>>> >> bus_width);
>>> >> >> >> >> +             } else if (hs_sdr) {
>>> >> >> >> >> +                     if (hs_sdr ==
>>> >> EXT_CSD_CARD_TYPE_SDR_1_2V) {
>>> >> >> >> >> +                             err =
>>> >> mmc_set_signal_voltage(host,
>>> >> >> >> >> +
>>> MMC_SIGNAL_VOLTAGE_120,
>>> >> 0);
>>> >> >> >> >> +                             if (err)
>>> >> >> >> >> +                                     goto err;
>>> >> >> >> >> +                     }
>>> >> >> >> >> +                     mmc_set_timing(card->host,
>>> >> >> MMC_TIMING_MMC_HS);
>>> >> >> >> >> +                     mmc_set_bus_width(card->host,
>>> >> bus_width);
>>> >> >> >> >>               }
>>> >> >> >> >>       }
>>> >> >> >> >>
>>> >> >> >> >> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
>>> >> >> >> >> index 1d5a3bd..c1d3ee3 100644
>>> >> >> >> >> --- a/drivers/mmc/core/sd.c
>>> >> >> >> >> +++ b/drivers/mmc/core/sd.c
>>> >> >> >> >> @@ -660,7 +660,8 @@ static int mmc_sd_init_uhs_card(struct
>>> >> >> mmc_card
>>> >> >> >> >> *card)
>>> >> >> >> >>
>>> >> >> >> >>       /* SPI mode doesn't define CMD19 */
>>> >> >> >> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
>>> >> >> >> >> >execute_tuning)
>>> >> >> >> >> -             err = card->host->ops->execute_tuning(card-
>>> >> >host);
>>> >> >> >> >> +             err = card->host->ops->execute_tuning(card-
>>> >> >host,
>>> >> >> >>   \
>>> >> >> >> >> +
>>> >> >> >> > MMC_SEND_TUNING_BLOCK);
>>> >> >> >> >>
>>> >> >> >> >>  out:
>>> >> >> >> >>       kfree(status);
>>> >> >> >> >> diff --git a/drivers/mmc/core/sdio.c
>>> b/drivers/mmc/core/sdio.c
>>> >> >> >> >> index 8c04f7f..8ef8817 100644
>>> >> >> >> >> --- a/drivers/mmc/core/sdio.c
>>> >> >> >> >> +++ b/drivers/mmc/core/sdio.c
>>> >> >> >> >> @@ -14,6 +14,7 @@
>>> >> >> >> >>
>>> >> >> >> >>  #include <linux/mmc/host.h>
>>> >> >> >> >>  #include <linux/mmc/card.h>
>>> >> >> >> >> +#include <linux/mmc/mmc.h>
>>> >> >> >> >>  #include <linux/mmc/sdio.h>
>>> >> >> >> >>  #include <linux/mmc/sdio_func.h>
>>> >> >> >> >>  #include <linux/mmc/sdio_ids.h>
>>> >> >> >> >> @@ -556,7 +557,8 @@ static int
>>> mmc_sdio_init_uhs_card(struct
>>> >> >> >> mmc_card
>>> >> >> >> >> *card)
>>> >> >> >> >>
>>> >> >> >> >>       /* Initialize and start re-tuning timer */
>>> >> >> >> >>       if (!mmc_host_is_spi(card->host) && card->host->ops-
>>> >> >> >> >> >execute_tuning)
>>> >> >> >> >> -             err = card->host->ops->execute_tuning(card-
>>> >> >host);
>>> >> >> >> >> +             err = card->host->ops->execute_tuning(card-
>>> >> >host,
>>> >> >> >> >> +
>>> >> >> >> > MMC_SEND_TUNING_BLOCK);
>>> >> >> >> >>
>>> >> >> >> >>  out:
>>> >> >> >> >>
>>> >> >> >> >> diff --git a/drivers/mmc/host/sdhci.c
>>> >> b/drivers/mmc/host/sdhci.c
>>> >> >> >> >> index a7c2311..13d74bb 100644
>>> >> >> >> >> --- a/drivers/mmc/host/sdhci.c
>>> >> >> >> >> +++ b/drivers/mmc/host/sdhci.c
>>> >> >> >> >> @@ -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
>>> >> >> >> >> @@ -1016,7 +1016,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
>>> >> >> */
>>> >> >> >> >> @@ -1673,7 +1674,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;
>>> >> >> >> >> @@ -1694,10 +1695,13 @@ static int
>>> sdhci_execute_tuning(struct
>>> >> >> >> mmc_host
>>> >> >> >> >> *mmc)
>>> >> >> >> >>        * Host Controller needs tuning only in case of
>>> SDR104
>>> >> mode
>>> >> >> >> >>        * and for SDR50 mode when Use Tuning for SDR50 is
>>> set
>>> >> in
>>> >> >> >> >>        * Capabilities register.
>>> >> >> >> >> +      * If the Host Controller supports the HS200 mode
>>> then
>>> >> >> tuning
>>> >> >> >> >> +      * function has to be executed.
>>> >> >> >> >>        */
>>> >> >> >> >>       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)))
>>> >> >> >> >> +         (host->flags & SDHCI_SDR50_NEEDS_TUNING)) ||
>>> >> >> >> >> +         (host->flags & SDHCI_HS200_NEEDS_TUNING))
>>> >> >> >> >>               ctrl |= SDHCI_CTRL_EXEC_TUNING;
>>> >> >> >> >>       else {
>>> >> >> >> >>               spin_unlock(&host->lock);
>>> >> >> >> >> @@ -1733,7 +1737,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;
>>> >> >> >> >> @@ -1748,7 +1752,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.
>>> >> >> >> >> @@ -2131,12 +2145,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;
>>> >> >> >> >> @@ -2741,6 +2757,10 @@ int sdhci_add_host(struct sdhci_host
>>> >> >> *host)
>>> >> >> >> >>       if (caps[1] & SDHCI_USE_SDR50_TUNING)
>>> >> >> >> >>               host->flags |= SDHCI_SDR50_NEEDS_TUNING;
>>> >> >> >> >>
>>> >> >> >> >> +     /* Does the host needs 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;
>>> >> >> >> >> diff --git a/include/linux/mmc/card.h
>>> >> b/include/linux/mmc/card.h
>>> >> >> >> >> index 534974c..e76f649 100644
>>> >> >> >> >> --- a/include/linux/mmc/card.h
>>> >> >> >> >> +++ b/include/linux/mmc/card.h
>>> >> >> >> >> @@ -209,6 +209,7 @@ struct mmc_card {
>>> >> >> >> >>  #define MMC_STATE_HIGHSPEED_DDR (1<<4)               /*
>>> card
>>> >> is
>>> >> >> in
>>> >> >> >> high
>>> >> >> >> >> speed mode */
>>> >> >> >> >>  #define MMC_STATE_ULTRAHIGHSPEED (1<<5)              /*
>>> card
>>> >> is
>>> >> >> in
>>> >> >> >> ultra
>>> >> >> >> >> high speed mode */
>>> >> >> >> >>  #define MMC_CARD_SDXC                (1<<6)          /*
>>> card
>>> >> is
>>> >> >> >> SDXC */
>>> >> >> >> >> +#define MMC_STATE_HIGHSPEED_200      (1<<7)  /* card is in
>>> >> HS200
>>> >> >> >> >> mode */
>>> >> >> >> >>       unsigned int            quirks;         /* card
>>> quirks
>>> >> */
>>> >> >> >> >>  #define MMC_QUIRK_LENIENT_FN0        (1<<0)          /*
>>> allow
>>> >> >> SDIO
>>> >> >> >> FN0
>>> >> >> >> >> writes outside of the VS CCCR range */
>>> >> >> >> >>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func-
>>> >> >> >> >> >cur_blksize */
>>> >> >> >> >> @@ -365,6 +366,7 @@ static inline void __maybe_unused
>>> >> >> >> >> remove_quirk(struct mmc_card *card, int data)
>>> >> >> >> >>  #define mmc_card_present(c)  ((c)->state &
>>> MMC_STATE_PRESENT)
>>> >> >> >> >>  #define mmc_card_readonly(c) ((c)->state &
>>> >> MMC_STATE_READONLY)
>>> >> >> >> >>  #define mmc_card_highspeed(c)        ((c)->state &
>>> >> >> >> MMC_STATE_HIGHSPEED)
>>> >> >> >> >> +#define mmc_card_hs200(c)    ((c)->state &
>>> >> >> MMC_STATE_HIGHSPEED_200)
>>> >> >> >> >>  #define mmc_card_blockaddr(c)        ((c)->state &
>>> >> >> >> MMC_STATE_BLOCKADDR)
>>> >> >> >> >>  #define mmc_card_ddr_mode(c) ((c)->state &
>>> >> >> MMC_STATE_HIGHSPEED_DDR)
>>> >> >> >> >>  #define mmc_card_uhs(c)              ((c)->state &
>>> >> >> >> >> MMC_STATE_ULTRAHIGHSPEED)
>>> >> >> >> >> @@ -374,6 +376,7 @@ static inline void __maybe_unused
>>> >> >> >> >> remove_quirk(struct mmc_card *card, int data)
>>> >> >> >> >>  #define mmc_card_set_present(c)      ((c)->state |=
>>> >> >> >> MMC_STATE_PRESENT)
>>> >> >> >> >>  #define mmc_card_set_readonly(c) ((c)->state |=
>>> >> >> MMC_STATE_READONLY)
>>> >> >> >> >>  #define mmc_card_set_highspeed(c) ((c)->state |=
>>> >> >> >> MMC_STATE_HIGHSPEED)
>>> >> >> >> >> +#define mmc_card_set_hs200(c)        ((c)->state |=
>>> >> >> >> >> MMC_STATE_HIGHSPEED_200)
>>> >> >> >> >>  #define mmc_card_set_blockaddr(c) ((c)->state |=
>>> >> >> >> MMC_STATE_BLOCKADDR)
>>> >> >> >> >>  #define mmc_card_set_ddr_mode(c) ((c)->state |=
>>> >> >> >> >> MMC_STATE_HIGHSPEED_DDR)
>>> >> >> >> >>  #define mmc_card_set_uhs(c) ((c)->state |=
>>> >> >> >> MMC_STATE_ULTRAHIGHSPEED)
>>> >> >> >> >> diff --git a/include/linux/mmc/host.h
>>> >> b/include/linux/mmc/host.h
>>> >> >> >> >> index 706f722..5eac57a 100644
>>> >> >> >> >> --- a/include/linux/mmc/host.h
>>> >> >> >> >> +++ b/include/linux/mmc/host.h
>>> >> >> >> >> @@ -50,6 +50,7 @@ struct mmc_ios {
>>> >> >> >> >>
>>> >> >> >> >>  #define MMC_TIMING_LEGACY    0
>>> >> >> >> >>  #define MMC_TIMING_MMC_HS    1
>>> >> >> >> >> +#define MMC_TIMING_MMC_HS200 2
>>> >> >> >> >>  #define MMC_TIMING_SD_HS     2
>>> >> >> >> >>  #define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY
>>> >> >> >> >>  #define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS
>>> >> >> >> >> @@ -60,6 +61,8 @@ struct mmc_ios {
>>> >> >> >> >>  #define MMC_SDR_MODE         0
>>> >> >> >> >>  #define MMC_1_2V_DDR_MODE    1
>>> >> >> >> >>  #define MMC_1_8V_DDR_MODE    2
>>> >> >> >> >> +#define MMC_1_2V_SDR_MODE    3
>>> >> >> >> >> +#define MMC_1_8V_SDR_MODE    4
>>> >> >> >> >>
>>> >> >> >> >>       unsigned char   signal_voltage;         /* signalling
>>> >> >> voltage
>>> >> >> >> >> (1.8V or 3.3V) */
>>> >> >> >> >>
>>> >> >> >> >> @@ -148,7 +151,9 @@ struct mmc_host_ops {
>>> >> >> >> >>       void    (*init_card)(struct mmc_host *host, struct
>>> >> mmc_card
>>> >> >> >> *card);
>>> >> >> >> >>
>>> >> >> >> >>       int     (*start_signal_voltage_switch)(struct
>>> mmc_host
>>> >> >> *host,
>>> >> >> >> >> struct mmc_ios *ios);
>>> >> >> >> >> -     int     (*execute_tuning)(struct mmc_host *host);
>>> >> >> >> >> +
>>> >> >> >> >> +     /* The tuning command opcode value is different for
>>> SD
>>> >> and
>>> >> >> >> eMMC
>>> >> >> >> >> cards */
>>> >> >> >> >> +     int     (*execute_tuning)(struct mmc_host *host, u32
>>> >> >> opcode);
>>> >> >> >> >>       void    (*enable_preset_value)(struct mmc_host *host,
>>> >> bool
>>> >> >> >> enable);
>>> >> >> >> >>       int     (*select_drive_strength)(unsigned int
>>> max_dtr,
>>> >> int
>>> >> >> >> >> host_drv, int card_drv);
>>> >> >> >> >>       void    (*hw_reset)(struct mmc_host *host);
>>> >> >> >> >> @@ -242,6 +247,10 @@ struct mmc_host {
>>> >> >> >> >>  #define MMC_CAP2_CACHE_CTRL  (1 << 1)        /* Allow
>>> cache
>>> >> >> control
>>> >> >> >> */
>>> >> >> >> >>  #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)    /* Notify
>>> >> poweroff
>>> >> >> >> >> supported */
>>> >> >> >> >>  #define MMC_CAP2_NO_MULTI_READ       (1 << 3)        /*
>>> >> >> Multiblock
>>> >> >> >> reads
>>> >> >> >> >> don't work */
>>> >> >> >> >> +#define MMC_CAP2_HS200_1_8V_SDR      (1 << 4)        /*
>>> can
>>> >> >> support
>>> >> >> >> */
>>> >> >> >> >> +#define MMC_CAP2_HS200_1_2V_SDR      (1 << 5)        /*
>>> can
>>> >> >> support
>>> >> >> >> */
>>> >> >> >> >> +#define MMC_CAP2_HS200
>>> (MMC_CAP2_HS200_1_8V_SDR
>>> >> |
>>> >> >> \
>>> >> >> >> >> +                              MMC_CAP2_HS200_1_2V_SDR)
>>> >> >> >> >>
>>> >> >> >> >>       mmc_pm_flag_t           pm_caps;        /* supported
>>> pm
>>> >> >> >> features */
>>> >> >> >> >>       unsigned int        power_notify_type;
>>> >> >> >> >> diff --git a/include/linux/mmc/mmc.h
>>> b/include/linux/mmc/mmc.h
>>> >> >> >> >> index 0e71356..7996272 100644
>>> >> >> >> >> --- a/include/linux/mmc/mmc.h
>>> >> >> >> >> +++ b/include/linux/mmc/mmc.h
>>> >> >> >> >> @@ -51,6 +51,7 @@
>>> >> >> >> >>  #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data
>>> >> addr
>>> >> >> R1
>>> >> >> >> >> */
>>> >> >> >> >>  #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data
>>> >> addr
>>> >> >> R1
>>> >> >> >> >> */
>>> >> >> >> >>  #define MMC_SEND_TUNING_BLOCK    19   /* adtc
>>> >> >>  R1
>>> >> >> >> >> */
>>> >> >> >> >> +#define MMC_SEND_TUNING_BLOCK_HS200  21      /* adtc R1
>>>  */
>>> >> >> >> >>
>>> >> >> >> >>    /* class 3 */
>>> >> >> >> >>  #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data
>>> >> addr
>>> >> >> R1
>>> >> >> >> >> */
>>> >> >> >> >> @@ -333,13 +334,76 @@ struct _mmc_csd {
>>> >> >> >> >>
>>> >> >> >> >>  #define EXT_CSD_CARD_TYPE_26 (1<<0)  /* Card can run at
>>> 26MHz
>>> >> */
>>> >> >> >> >>  #define EXT_CSD_CARD_TYPE_52 (1<<1)  /* Card can run at
>>> 52MHz
>>> >> */
>>> >> >> >> >> -#define EXT_CSD_CARD_TYPE_MASK       0xF     /* Mask out
>>> >> >> reserved
>>> >> >> >> bits */
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_MASK       0x3F    /* Mask out
>>> >> >> reserved
>>> >> >> >> bits */
>>> >> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can
>>> run
>>> >> at
>>> >> >> >> 52MHz
>>> >> >> >> >> */
>>> >> >> >> >>                                            /* DDR mode
>>> @1.8V
>>> >> or
>>> >> >> 3V
>>> >> >> >> I/O */
>>> >> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can
>>> run
>>> >> at
>>> >> >> >> 52MHz
>>> >> >> >> >> */
>>> >> >> >> >>                                            /* DDR mode
>>> @1.2V
>>> >> I/O
>>> >> >> */
>>> >> >> >> >>  #define EXT_CSD_CARD_TYPE_DDR_52
>>> >> >> (EXT_CSD_CARD_TYPE_DDR_1_8V
>>> >> >> >>  \
>>> >> >> >> >>                                       |
>>> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V)
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V   (1<<4)  /* Card can
>>> run
>>> >> at
>>> >> >> >> >> 200MHz */
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V   (1<<5)  /* Card can
>>> run
>>> >> at
>>> >> >> >> >> 200MHz */
>>> >> >> >> >> +                                             /* SDR mode
>>> >> @1.2V
>>> >> >> I/O
>>> >> >> >> */
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_200
>>> >>  (EXT_CSD_CARD_TYPE_SDR_1_8V
>>> >> >> >>   \
>>> >> >> >> >> +                                     |
>>> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL
>>> >>  (EXT_CSD_CARD_TYPE_SDR_200
>>> >> >> >>  \
>>> >> >> >> >> +                                     |
>>> EXT_CSD_CARD_TYPE_52
>>> >> >> >>  \
>>> >> >> >> >> +                                     |
>>> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_2V_ALL
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V     \
>>> >> >> >> >> +                                     |
>>> EXT_CSD_CARD_TYPE_52
>>> >> >> >>  \
>>> >> >> >> >> +                                     |
>>> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define      EXT_CSD_CARD_TYPE_SDR_1_8V_ALL
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V     \
>>> >> >> >> >> +                                     |
>>> EXT_CSD_CARD_TYPE_52
>>> >> >> >>  \
>>> >> >> >> >> +                                     |
>>> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_8V
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V
>>> >> >> >> >>       (EXT_CSD_CARD_TYPE_SDR_200   \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_1_2V
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >> +
>>> >> >> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52
>>> >> >> >> (EXT_CSD_CARD_TYPE_SDR_200
>>> >> >> >> >> \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_DDR_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> EXT_CSD_CARD_TYPE_52
>>> >> >> >> > \
>>> >> >> >> >> +                                             |
>>> >> >> >> EXT_CSD_CARD_TYPE_26)
>>> >> >> >> >>
>>> >> >> >> >>  #define EXT_CSD_BUS_WIDTH_1  0       /* Card is in 1 bit
>>> mode
>>> >> */
>>> >> >> >> >>  #define EXT_CSD_BUS_WIDTH_4  1       /* Card is in 4 bit
>>> mode
>>> >> */
>>> >> >> >> >> diff --git a/include/linux/mmc/sdhci.h
>>> >> >> b/include/linux/mmc/sdhci.h
>>> >> >> >> >> index e4b6935..d9a2222 100644
>>> >> >> >> >> --- a/include/linux/mmc/sdhci.h
>>> >> >> >> >> +++ b/include/linux/mmc/sdhci.h
>>> >> >> >> >> @@ -121,6 +121,7 @@ struct sdhci_host {
>>> >> >> >> >>  #define SDHCI_AUTO_CMD23     (1<<7)  /* Auto CMD23 support
>>> */
>>> >> >> >> >>  #define SDHCI_PV_ENABLED     (1<<8)  /* Preset value
>>> enabled
>>> >> */
>>> >> >> >> >>  #define SDHCI_SDIO_IRQ_ENABLED       (1<<9)  /* SDIO irq
>>> >> enabled
>>> >> >> */
>>> >> >> >> >> +#define SDHCI_HS200_NEEDS_TUNING (1<<10)     /* HS200
>>> needs
>>> >> >> tuning
>>> >> >> >> */
>>> >> >> >> >>
>>> >> >> >> >>       unsigned int version;   /* SDHCI spec. version */
>>> >> >> >> >>
>>> >> >> >> >> --
>>> >> >> >> >> 1.7.1
>>> >> >> >> >>
>>> >> >> >> >> --
>>> >> >> >> >> To unsubscribe from this list: send the line "unsubscribe
>>> >> linux-
>>> >> >> mmc"
>>> >> >> >> in
>>> >> >> >> >> the body of a message to majordomo@vger.kernel.org
>>> >> >> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
>>> >> >> info.html
>>> >> >> >> >
>>> >> >> >> > --
>>> >> >> >> > To unsubscribe from this list: send the line "unsubscribe
>>> >> linux-
>>> >> >> mmc"
>>> >> >> >> in
>>> >> >> >> > the body of a message to majordomo@vger.kernel.org
>>> >> >> >> > More majordomo info at  http://vger.kernel.org/majordomo-
>>> >> info.html
>>> >> >> >> >
>>> >> >> >> --
>>> >> >> >> To unsubscribe from this list: send the line "unsubscribe
>>> linux-
>>> >> mmc"
>>> >> >> in
>>> >> >> >> the body of a message to majordomo@vger.kernel.org
>>> >> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
>>> >> info.html
>>> >> >> >
>>> >> >> --
>>> >> >> To unsubscribe from this list: send the line "unsubscribe linux-
>>> mmc"
>>> >> in
>>> >> >> the body of a message to majordomo@vger.kernel.org
>>> >> >> More majordomo info at  http://vger.kernel.org/majordomo-
>>> info.html
>>> >> >
>>> >
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Girish K S Dec. 13, 2011, 4:43 a.m. UTC | #13
On 12 December 2011 12:20, Girish K S <girish.shivananjappa@linaro.org> wrote:
> On 5 December 2011 20:29, Saugata Das <saugata.das@linaro.org> wrote:
>> Hi Girish
>>
>> Please refer to Figure 71 (HS200 device output timing) of the MMC-4.5
>> spec. It shows that both CMD and DATA[7-0] will have some latency till
>> valid window. This implies that even the CMD line will need tuning for
>> reading the response. The specification talks about identifying
>> sampling point for data lines by reading tuning blocks. Based on host
>> controller capability, even the CMD line will get the good sample
>> point during the same tuning sequence.
>>
>> We need to have the tuning done (execute_tuning) soon after switching
>> to HS200 mode and 200MHz clock.
>>
> If i make a change as per subhash suggestion"set bus width before
> setting the HS200 mode." then it will affect the entire frame work of
> mmc which is developed as per Annexure A6.1 A.6.2 A.6.3 (mentions the
> steps for bus initialization). can any of you suggest a way to do
> this.

Any inputs on this

>>
>> Regards
>> Saugata
>>
>>
>> On 5 December 2011 16:59, Subhash Jadavani <subhashj@codeaurora.org> wrote:
>>>
>>>
>>>> -----Original Message-----
>>>> From: Girish K S [mailto:girish.shivananjappa@linaro.org]
>>>> Sent: Monday, December 05, 2011 12:20 PM
>>>> To: Subhash Jadavani
>>>> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>>>> soc@vger.kernel.org; Chris Ball
>>>> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>>>>
>>>> On 5 December 2011 11:46, Subhash Jadavani <subhashj@codeaurora.org>
>>>> wrote:
>>>> >
>>>> >
>>>> >> -----Original Message-----
>>>> >> From: Girish K S [mailto:girish.shivananjappa@linaro.org]
>>>> >> Sent: Friday, December 02, 2011 5:08 PM
>>>> >> To: Subhash Jadavani
>>>> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>>>> >> soc@vger.kernel.org; Chris Ball
>>>> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>>>> >>
>>>> >> On 2 December 2011 00:02, Subhash Jadavani <subhashj@codeaurora.org>
>>>> >> wrote:
>>>> >> >
>>>> >> >
>>>> >> >> -----Original Message-----
>>>> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>>>> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
>>>> >> >> Sent: Thursday, December 01, 2011 7:48 PM
>>>> >> >> To: Subhash Jadavani
>>>> >> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-samsung-
>>>> >> >> soc@vger.kernel.org; Chris Ball
>>>> >> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC
>>>> 4.5
>>>> >> >>
>>>> >> >> On 1 December 2011 16:27, Subhash Jadavani
>>>> <subhashj@codeaurora.org>
>>>> >> >> wrote:
>>>> >> >> >
>>>> >> >> >
>>>> >> >> >> -----Original Message-----
>>>> >> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>>>> >> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
>>>> >> >> >> Sent: Thursday, December 01, 2011 3:58 PM
>>>> >> >> >> To: Subhash Jadavani
>>>> >> >> >> Cc: linux-mmc@vger.kernel.org; patches@linaro.org; linux-
>>>> samsung-
>>>> >> >> >> soc@vger.kernel.org; Chris Ball
>>>> >> >> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC
>>>> >> 4.5
>>>> >> >> >>
>>>> >> >> >> On 1 December 2011 15:33, Subhash Jadavani
>>>> >> <subhashj@codeaurora.org>
>>>> >> >> >> wrote:
>>>> >> >> >> > Hi Girish,
>>>> >> >> >> >
>>>> >> >> >> >> -----Original Message-----
>>>> >> >> >> >> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>>>> >> >> >> >> owner@vger.kernel.org] On Behalf Of Girish K S
>>>> >> >> >> >> Sent: Wednesday, November 30, 2011 2:24 PM
>>>> >> >> >> >> To: linux-mmc@vger.kernel.org
>>>> >> >> >> >> Cc: patches@linaro.org; linux-samsung-soc@vger.kernel.org;
>>>> >> >> >> >> subhashj@codeaurora.org; Girish K S; Chris Ball
>>>> >> >> >> >> Subject: [PATCH V5] mmc: core: HS200 mode support for eMMC
>>>> 4.5
>>>> >> >> >> >>
>>>> >> >> >> >> This patch adds the support of the HS200 bus speed for eMMC
>>>> >> 4.5
>>>> >> >> >> >> devices.
>>>> >> >> >> >> The eMMC 4.5 devices have support for 200MHz bus speed.The
>>>> mmc
>>>> >> >> core
>>>> >> >> >> and
>>>> >> >> >> >> host modules have been touched to add support for this
>>>> module.
>>>> >> >> >> >>
>>>> >> >> >> >> It is necessary to know the card type in the sdhci.c file
>>>> to
>>>> >> add
>>>> >> >> >> >> support
>>>> >> >> >> >> for eMMC tuning function. So card.h file is included to
>>>> import
>>>> >> >> the
>>>> >> >> >> card
>>>> >> >> >> >> data structure.
>>>> >> >> >> >>
>>>> >> >> >> >> cc: Chris Ball <cjb@laptop.org>
>>>> >> >> >> >> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
>>>> >> >> >> >> ---
>>>> >> >> >> >> Changes in v5:
>>>> >> >> >> >>       Reduced the case statements for better code
>>>> readability.
>>>> >> >> >> Removed
>>>> >> >> >> >>       unused macro definitions. Modified the tuning
>>>> function
>>>> >> >> >> prototype
>>>> >> >> >> >>       and definition to support tuning for both SD and eMMC
>>>> >> >> cards.
>>>> >> >> >> >> Changes in v4:
>>>> >> >> >> >>       Rebased onto chris-mmc/mmc-next branch. This patch is
>>>> >> >> >> >> successfully
>>>> >> >> >> >>       applied on commit with id
>>>> >> >> >> >> de022ed3fdc14808299b2fa66dbb1ed5ab921912.
>>>> >> >> >> >> Changes in v3:
>>>> >> >> >> >>       In the previous commits of chris-mmc/mmc-next branch,
>>>> >> the
>>>> >> >> >> patch
>>>> >> >> >> >> with
>>>> >> >> >> >>       commit id (c0f22a2c92e357e7cb3988b0b13034d70b7461f9)
>>>> >> >> defines
>>>> >> >> >> >> caps2 for
>>>> >> >> >> >>       more capabilities. This patch version deletes the
>>>> member
>>>> >> >> >> >> ext_caps(created
>>>> >> >> >> >>       in my earlier patch) from struct mmc_host and reuses
>>>> >> >> already
>>>> >> >> >> >> accepted
>>>> >> >> >> >>       caps2 member.
>>>> >> >> >> >> Changes in v2:
>>>> >> >> >> >>       Rebased to latest chris-mmc/mmc-next branch. Resolved
>>>> >> >> >> indentation
>>>> >> >> >> >>       problems identified in review. This patch has to be
>>>> >> applied
>>>> >> >> >> >> before
>>>> >> >> >> >>       the patch released for modifying the printk messages.
>>>> >> >> >> >> Changes in v1:
>>>> >> >> >> >>       Case statements in switch that produce same result
>>>> have
>>>> >> >> >> >>       been combined to reduce repeated assignments.
>>>> >> >> >> >>       patch recreated after rebase to chris balls mmc-next
>>>> >> >> branch.
>>>> >> >> >> >>
>>>> >> >> >> >>  drivers/mmc/core/bus.c    |    3 +-
>>>> >> >> >> >>  drivers/mmc/core/mmc.c    |   77
>>>> >> >> >> >> ++++++++++++++++++++++++++++++++++++++++----
>>>> >> >> >> >>  drivers/mmc/core/sd.c     |    3 +-
>>>> >> >> >> >>  drivers/mmc/core/sdio.c   |    4 ++-
>>>> >> >> >> >>  drivers/mmc/host/sdhci.c  |   38 +++++++++++++++++-----
>>>> >> >> >> >>  include/linux/mmc/card.h  |    3 ++
>>>> >> >> >> >>  include/linux/mmc/host.h  |   11 ++++++-
>>>> >&g