Re: [PATCH V6 2/2] mmc: host: Adds support for eMMC 4.5 HS200 mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



HI,

minor comments below.

Philip

On Dec 18, 2011, at 10:36 PM, Girish K S wrote:

> This patch adds support for the HS200 mode on the host side.
> Also enables the tuning feature required when the HS200 mode
> is selected.
> 
> cc: Chris Ball <cjb@xxxxxxxxxx>
> Signed-off-by: Girish K S <girish.shivananjappa@xxxxxxxxxx>
> ---
> drivers/mmc/host/sdhci.c  |   43 +++++++++++++++++++++++++++++++++----------
> drivers/mmc/host/sdhci.h  |    1 +
> include/linux/mmc/host.h  |   11 ++++++++++-
> include/linux/mmc/sdhci.h |    1 +
> 4 files changed, 45 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index ab6018f..049d51d 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 */
> @@ -1375,7 +1376,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
> 		    (ios->timing == MMC_TIMING_UHS_SDR104) ||
> 		    (ios->timing == MMC_TIMING_UHS_DDR50) ||
> 		    (ios->timing == MMC_TIMING_UHS_SDR25) ||
> -		    (ios->timing == MMC_TIMING_UHS_SDR12))
> +		    (ios->timing == MMC_TIMING_UHS_SDR12) ||
> +		    (ios->timing == MMC_TIMING_MMC_HS200))
> 			ctrl |= SDHCI_CTRL_HISPD;

move to first test so speed ordering is maintained.
> 
> 		ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> @@ -1435,6 +1437,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
> 				ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
> 			else if (ios->timing == MMC_TIMING_UHS_DDR50)
> 				ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
> +			else if (ios->timing == MMC_TIMING_MMC_HS200)
> +				ctrl_2 |= SDHCI_CTRL_HS_SDR200;
> 			sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
> 		}

same as above

> 
> @@ -1673,7 +1677,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)
> {

Can one deduce the type of tuning needed by the speed ?   is the opcode really needed?

> 	struct sdhci_host *host;
> 	u16 ctrl;
> @@ -1694,10 +1698,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 +1740,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 +1755,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 +2148,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 +2760,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/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index a04d4d0..46fd2ac 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -158,6 +158,7 @@
> #define   SDHCI_CTRL_UHS_SDR50		0x0002
> #define   SDHCI_CTRL_UHS_SDR104		0x0003
> #define   SDHCI_CTRL_UHS_DDR50		0x0004
> +#define   SDHCI_CTRL_HS_SDR200		0x0005 /*reserved value in SDIO spec */
> #define  SDHCI_CTRL_VDD_180		0x0008
> #define  SDHCI_CTRL_DRV_TYPE_MASK	0x0030
> #define   SDHCI_CTRL_DRV_TYPE_B		0x0000
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 9a03d03..606c8c3 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -56,10 +56,13 @@ struct mmc_ios {
> #define MMC_TIMING_UHS_SDR50	3
> #define MMC_TIMING_UHS_SDR104	4
> #define MMC_TIMING_UHS_DDR50	5
> +#define MMC_TIMING_MMC_HS200	6
> 
> #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/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@xxxxxxxxxxxxxxx
> 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@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux