diff mbox

mmc: Add support for eMMC Dual Data Rate

Message ID 7E008078-5B62-4418-857B-DBFF1E70E6D3@marvell.com (mailing list archive)
State New, archived
Headers show

Commit Message

Philip Rakity April 22, 2011, 8:27 p.m. UTC
eMMC voltage change not required for 1.8V.  3.3V and 1.8V vcc
are capable of doing DDR. vccq of 1.8v is not required.

Signed-off-by: Philip Rakity <prakity@marvell.com>
---
 drivers/mmc/core/core.c  |   14 ++------------
 drivers/mmc/core/core.h  |    2 --
 drivers/mmc/core/mmc.c   |   33 ++++++++++++++++++++++++++++-----
 include/linux/mmc/host.h |    1 +
 4 files changed, 31 insertions(+), 19 deletions(-)

Comments

Arindam Nath April 26, 2011, 7:04 a.m. UTC | #1
Hi Philip,


> -----Original Message-----
> From: Philip Rakity [mailto:prakity@marvell.com]
> Sent: Saturday, April 23, 2011 1:57 AM
> To: linux-mmc@vger.kernel.org
> Cc: Nath, Arindam
> Subject: [PATCH] mmc: Add support for eMMC Dual Data Rate
> 
> 
> eMMC voltage change not required for 1.8V.  3.3V and 1.8V vcc
> are capable of doing DDR. vccq of 1.8v is not required.
> 
> Signed-off-by: Philip Rakity <prakity@marvell.com>
> ---
>  drivers/mmc/core/core.c  |   14 ++------------
>  drivers/mmc/core/core.h  |    2 --
>  drivers/mmc/core/mmc.c   |   33 ++++++++++++++++++++++++++++-----
>  include/linux/mmc/host.h |    1 +
>  4 files changed, 31 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index 91ab31f..69df00c 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -720,22 +720,12 @@ void mmc_set_bus_mode(struct mmc_host *host,
> unsigned int mode)
>  }
> 
>  /*
> - * Change data bus width and DDR mode of a host.
> - */
> -void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
> -			   unsigned int ddr)
> -{
> -	host->ios.bus_width = width;
> -	host->ios.ddr = ddr;
> -	mmc_set_ios(host);
> -}
> -
> -/*
>   * Change data bus width of a host.
>   */
>  void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
>  {
> -	mmc_set_bus_width_ddr(host, width, MMC_SDR_MODE);
> +	host->ios.bus_width = width;
> +	mmc_set_ios(host);
>  }
> 
>  /**
> diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
> index 6114ca5..c5d0e8b 100644
> --- a/drivers/mmc/core/core.h
> +++ b/drivers/mmc/core/core.h
> @@ -38,8 +38,6 @@ void mmc_ungate_clock(struct mmc_host *host);
>  void mmc_set_ungated(struct mmc_host *host);
>  void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
>  void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
> -void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
> -			   unsigned int ddr);
>  u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
>  void mmc_set_timing(struct mmc_host *host, unsigned int timing);
>  void mmc_set_driver_type(struct mmc_host *host, unsigned int
> drv_type);
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index ba1c878..f4b675b 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -20,6 +20,7 @@
>  #include "core.h"
>  #include "bus.h"
>  #include "mmc_ops.h"
> +#include "sd_ops.h"
> 
>  static const unsigned int tran_exp[] = {
>  	10000,		100000,		1000000,	10000000,
> @@ -633,10 +634,12 @@ static int mmc_init_card(struct mmc_host *host,
> u32 ocr,
>  	 */
>  	if (mmc_card_highspeed(card)) {
>  		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
> -			&& (host->caps & (MMC_CAP_1_8V_DDR)))
> +			&& ((host->caps & (MMC_CAP_1_8V_DDR |
> MMC_CAP_UHS_DDR50))
> +				== (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50)))
>  				ddr = MMC_1_8V_DDR_MODE;
>  		else if ((card->ext_csd.card_type &
> EXT_CSD_CARD_TYPE_DDR_1_2V)
> -			&& (host->caps & (MMC_CAP_1_2V_DDR)))
> +			&& ((host->caps & (MMC_CAP_1_2V_DDR |
> MMC_CAP_UHS_DDR50))
> +				== (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50)))
>  				ddr = MMC_1_2V_DDR_MODE;
>  	}
> 
> @@ -670,8 +673,7 @@ static int mmc_init_card(struct mmc_host *host, u32
> ocr,
>  					 ext_csd_bits[idx][0],
>  					 0);
>  			if (!err) {
> -				mmc_set_bus_width_ddr(card->host,
> -						      bus_width, MMC_SDR_MODE);
> +				mmc_set_bus_width(card->host, bus_width);
>  				/*
>  				 * If controller can't handle bus width test,
>  				 * use the highest bus width to maintain
> @@ -697,8 +699,29 @@ static int mmc_init_card(struct mmc_host *host,
> u32 ocr,
>  				1 << bus_width, ddr);
>  			goto free_card;
>  		} else if (ddr) {
> +			/*
> +			 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
> +			 * signaling.
> +			 *
> +			 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V
> vccq.
> +			 *
> +			 * 1.8V vccq at 3.3V core voltage (vcc) is not
> required
> +			 * in the JEDEC spec for DDR.
> +			 *
> +			 * Do not force change in vccq since we are obviously
> +			 * working and no change to vccq is needed.
> +			 *
> +			 * WARNING: eMMC rules are NOT the same as SD DDR
> +			 */
> +			if (ddr == EXT_CSD_CARD_TYPE_DDR_1_2V) {
> +				err = mmc_set_signal_voltage(host,
> +					MMC_SIGNAL_VOLTAGE_120, 0);

Will this call really have any effect? *cmd11* argument is 0, so CMD11 won't be sent in this case. Also since there is no handler in my sdhci_start_signal_voltage_switch() for MMC_SIGNAL_VOLTAGE_120, the function will simply return 0.

Thanks,
Arindam


--
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
diff mbox

Patch

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 91ab31f..69df00c 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -720,22 +720,12 @@  void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
 }
 
 /*
- * Change data bus width and DDR mode of a host.
- */
-void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
-			   unsigned int ddr)
-{
-	host->ios.bus_width = width;
-	host->ios.ddr = ddr;
-	mmc_set_ios(host);
-}
-
-/*
  * Change data bus width of a host.
  */
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
 {
-	mmc_set_bus_width_ddr(host, width, MMC_SDR_MODE);
+	host->ios.bus_width = width;
+	mmc_set_ios(host);
 }
 
 /**
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 6114ca5..c5d0e8b 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -38,8 +38,6 @@  void mmc_ungate_clock(struct mmc_host *host);
 void mmc_set_ungated(struct mmc_host *host);
 void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
-void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
-			   unsigned int ddr);
 u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
 void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index ba1c878..f4b675b 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -20,6 +20,7 @@ 
 #include "core.h"
 #include "bus.h"
 #include "mmc_ops.h"
+#include "sd_ops.h"
 
 static const unsigned int tran_exp[] = {
 	10000,		100000,		1000000,	10000000,
@@ -633,10 +634,12 @@  static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	if (mmc_card_highspeed(card)) {
 		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
-			&& (host->caps & (MMC_CAP_1_8V_DDR)))
+			&& ((host->caps & (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50))
+				== (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50)))
 				ddr = MMC_1_8V_DDR_MODE;
 		else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
-			&& (host->caps & (MMC_CAP_1_2V_DDR)))
+			&& ((host->caps & (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50))
+				== (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50)))
 				ddr = MMC_1_2V_DDR_MODE;
 	}
 
@@ -670,8 +673,7 @@  static int mmc_init_card(struct mmc_host *host, u32 ocr,
 					 ext_csd_bits[idx][0],
 					 0);
 			if (!err) {
-				mmc_set_bus_width_ddr(card->host,
-						      bus_width, MMC_SDR_MODE);
+				mmc_set_bus_width(card->host, bus_width);
 				/*
 				 * If controller can't handle bus width test,
 				 * use the highest bus width to maintain
@@ -697,8 +699,29 @@  static int mmc_init_card(struct mmc_host *host, u32 ocr,
 				1 << bus_width, ddr);
 			goto free_card;
 		} else if (ddr) {
+			/*
+			 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
+			 * signaling.
+			 *
+			 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
+			 *
+			 * 1.8V vccq at 3.3V core voltage (vcc) is not required
+			 * in the JEDEC spec for DDR.
+			 *
+			 * Do not force change in vccq since we are obviously
+			 * working and no change to vccq is needed.
+			 *
+			 * WARNING: eMMC rules are NOT the same as SD DDR
+			 */
+			if (ddr == EXT_CSD_CARD_TYPE_DDR_1_2V) {
+				err = mmc_set_signal_voltage(host,
+					MMC_SIGNAL_VOLTAGE_120, 0);
+				if (err)
+					goto err;
+			}
 			mmc_card_set_ddr_mode(card);
-			mmc_set_bus_width_ddr(card->host, bus_width, ddr);
+			mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
+			mmc_set_bus_width(card->host, bus_width);
 		}
 	}
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 9beb6c5..b8942fc 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -66,6 +66,7 @@  struct mmc_ios {
 
 #define MMC_SIGNAL_VOLTAGE_330	0
 #define MMC_SIGNAL_VOLTAGE_180	1
+#define MMC_SIGNAL_VOLTAGE_120	2
 
 	unsigned char	drv_type;		/* driver type (A, B, C, D) */