Re: [PATCH v2 1/1] sdhci support emmc ddr50 mode

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

 



On Dec 6, 2010, at 4:15 AM, Zhangfei Gao wrote:

> From f2194b46c2c3ded86009d36a4a8b4eebb7d0b9eb Mon Sep 17 00:00:00 2001
> From: Zhangfei Gao <zhangfei.gao@xxxxxxxxxxx>
> Date: Fri, 3 Dec 2010 07:21:15 -0500
> Subject: [PATCH] mmc: sdhci support emmc ddr50 mode
> 
> 	1. spec 3.0 does not claim support 1.2v ddr mode
> 	2. Call back function set_power is added, since some controller count
> on external pmic to provide power
> 
> Signed-off-by: Zhangfei Gao <zhangfei.gao@xxxxxxxxxxx>
> ---
> drivers/mmc/core/core.c   |    8 ++++++++
> drivers/mmc/host/sdhci.c  |   36 +++++++++++++++++++++++++++++++++++-
> drivers/mmc/host/sdhci.h  |   14 ++++++++++++--
> include/linux/mmc/mmc.h   |    1 +
> include/linux/mmc/sdhci.h |    2 ++
> 5 files changed, 58 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index 8bf542c..8f172cd 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -1573,6 +1573,14 @@ void mmc_rescan(struct work_struct *work)
> 		 */
> 		err = mmc_send_op_cond(host, 0, &ocr);
> 		if (!err) {
> +			if ((ocr & MMC_CARD_1_8V)
> +				&& (host->ocr_avail & MMC_CARD_1_8V)) {
> +				/* switch voltage to 1.8v */
> +				mmc_power_off(host);
> +				host->ocr = ocr & host->ocr_avail;
> +				mmc_power_up(host);
> +			}
> +

is the 1.2v case missing ? 

/*
 * Mask off any voltages we don't support and select
 * the lowest voltage
 */
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)

Doesn't this code already handle the voltage correctly ?


> 			if (mmc_attach_mmc(host, ocr))
> 				mmc_power_off(host);
> 			goto out;
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index a25db42..b7ad2f6 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -982,6 +982,22 @@ static void sdhci_finish_command(struct sdhci_host *host)
> 	host->cmd = NULL;
> }
> 
> +static void sdhci_set_ddr(struct sdhci_host *host, unsigned int ddr)
> +{
> +	u16 con;
> +
> +	if (ddr == MMC_SDR_MODE)
> +		return;
> +
> +	con = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> +	if (con & SDHCI_CTRL2_1_8V) {
> +		con &= ~SDHCI_CTRL2_UHS_MASK;
> +		if (ddr & MMC_1_8V_DDR_MODE)
> +			con |= SDHCI_CTRL2_DDR50;
> +		sdhci_writew(host, con, SDHCI_HOST_CONTROL2);
> +	}
> +}
> +


The host controller should not enable the CAP if 1.8V is not supported.  DDR should not be 
invoked if CAP is not set.  Thus

> +	if (con & SDHCI_CTRL2_1_8V) {

and
> +		if (ddr & MMC_1_8V_DDR_MODE)

are not needed.

This code should move to driver specific function since tuning may be done on some systems and
some systems (not mmp2) may need to delay the 5ms for voltage to be stable.  Would prefer a
host->ops callback.

> static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
> {
> 	int div;
> @@ -1080,6 +1096,17 @@ static void sdhci_set_power(struct sdhci_host
> *host, unsigned short power)
> 		return;
> 	}
> 
> +	if (pwr == SDHCI_POWER_180) {
> +		u16 con;
> +
> +		con = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> +		con |= SDHCI_CTRL2_1_8V;
> +		sdhci_writew(host, con, SDHCI_HOST_CONTROL2);
> +
> +		if (host->ops->set_power)
> +			host->ops->set_power(host, pwr);
> +	}
> +

This code should be moved to sdhci_set_ddr (aboe).  Not needed if voltage is 1.8v and card
is not running ddr.

> 	/*
> 	 * Spec says that we should clear the power reg before setting
> 	 * a new value. Some controllers don't seem to like this though.
> @@ -1176,6 +1203,7 @@ static void sdhci_set_ios(struct mmc_host *mmc,
> struct mmc_ios *ios)
> 	}
> 
> 	sdhci_set_clock(host, ios->clock);
> +	sdhci_set_ddr(host, ios->ddr);
> 
> 	if (ios->power_mode == MMC_POWER_OFF)
> 		sdhci_set_power(host, -1);
> @@ -1736,7 +1764,7 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host);
> int sdhci_add_host(struct sdhci_host *host)
> {
> 	struct mmc_host *mmc;
> -	unsigned int caps;
> +	unsigned int caps, caps_h;
> 	int ret;
> 
> 	WARN_ON(host == NULL);
> @@ -1761,6 +1789,12 @@ int sdhci_add_host(struct sdhci_host *host)
> 
> 	caps = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
> 		sdhci_readl(host, SDHCI_CAPABILITIES);
> +	caps_h = sdhci_readl(host, SDHCI_CAPABILITIES_H);
> +
> +	if (caps & SDHCI_CAN_VDD_180) {
> +		if (caps_h & SDHCI_CAN_SDR50)
> +			mmc->caps |= (MMC_CAP_1_8V_DDR);
> +	}
> 
> 	if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
> 		host->flags |= SDHCI_USE_SDMA;
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index b689cc6..28c460a 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -144,7 +144,14 @@
> 
> #define SDHCI_ACMD12_ERR	0x3C
> 
> -/* 3E-3F reserved */
> +#define SDHCI_HOST_CONTROL2	0x3E
> +#define  SDHCI_CTRL2_UHS_MASK	0x0007
> +#define   SDHCI_CTRL2_SDR12	0x0000
> +#define   SDHCI_CTRL2_SDR25	0x0001
> +#define   SDHCI_CTRL2_SDR50	0x0002
> +#define   SDHCI_CTRL2_SDR104	0x0003
> +#define   SDHCI_CTRL2_DDR50	0x0004
> +#define  SDHCI_CTRL2_1_8V	0x0008
> 
> #define SDHCI_CAPABILITIES	0x40
> #define  SDHCI_TIMEOUT_CLK_MASK	0x0000003F
> @@ -165,7 +172,10 @@
> #define  SDHCI_CAN_VDD_180	0x04000000
> #define  SDHCI_CAN_64BIT	0x10000000
> 
> -/* 44-47 reserved for more caps */
> +#define SDHCI_CAPABILITIES_H	0x44
> +#define  SDHCI_CAN_SDR50	0x00000001
> +#define  SDHCI_CAN_SDR104	0x00000002
> +#define  SDHCI_CAN_DDR50	0x00000004
> 
> #define SDHCI_MAX_CURRENT	0x48
> 
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 956fbd8..bd09b19 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -202,6 +202,7 @@ struct _mmc_csd {
>  * OCR bits are mostly in host.h
>  */
> #define MMC_CARD_BUSY	0x80000000	/* Card Power up status bit */
> +#define MMC_CARD_1_8V	0x00000080	/* Card 1.70-1.95V support bit */
> 
> /*
>  * Card Command Classes (CCC)
> diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
> index 86e8380..57bcda9 100644
> --- a/include/linux/mmc/sdhci.h
> +++ b/include/linux/mmc/sdhci.h
> @@ -163,6 +163,8 @@ struct sdhci_ops {
> 	void (*platform_send_init_74_clocks)(struct sdhci_host *host,
> 					     u8 power_mode);
> 	unsigned int    (*get_ro)(struct sdhci_host *host);
> +	unsigned int    (*set_power)(struct sdhci_host *host,
> +				unsigned short power);
> };
> 
> 
> -- 
> 1.7.0.4
> 
> Update the condition of voltage switch.
> +			if ((ocr & MMC_CARD_1_8V)
> +				&& (host->ocr_avail & MMC_CARD_1_8V)) {
> +				/* switch voltage to 1.8v */
> 
> Any comments are welcome.
> --
> 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