All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v10 00/12] mmc: sdhci: fixes and enhancements
@ 2012-12-17 11:21 Kevin Liu
  2012-12-17 11:21 ` [PATCH v10 01/12] mmc: sdhci: fix transfer mode setting bug for cmds w/o data transfer Kevin Liu
                   ` (11 more replies)
  0 siblings, 12 replies; 14+ messages in thread
From: Kevin Liu @ 2012-12-17 11:21 UTC (permalink / raw)
  To: linux-mmc, cjb, arindam.nath, peppe.cavallaro, ulf.hansson,
	andriy.shevchenko, prakity
  Cc: zhangfei.gao, haojian.zhuang, cxie4, keyuan.liu


This patchset aim to fix bugs and do some code enhancement for sdhci.c.
Most patches are quite small.
I will highly appreciate if you can pay a few minutes to review them.
Any comments are welcome.

[PATCH v10 01/12] mmc: sdhci: fix transfer mode setting bug for cmds w/o data transfer
[PATCH v10 02/12] mmc: sdhci: refine code for clock disable/enable in set ios
[PATCH v10 03/12] mmc: sdhci: add function to get retunig timer count
[PATCH v10 04/12] mmc: sdhci: correct voltage support caps setting
[PATCH v10 05/12] mmc: sdhci: clean code for SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK selected
[PATCH v10 06/12] mmc: sdhci: remove check for CONFIG_REGULATOR
[PATCH v10 07/12] mmc: sdhci: fix the bug that DDR50 can't work for emmc in default code
[PATCH v10 08/12] mmc: sdhci: remove set_uhs_signaling function
[PATCH v10 09/12] mmc: sdhci: enhance preset value function
[PATCH v10 10/12] mmc: sdhci: keep the saved clock var up to date
[PATCH v10 11/12] mmc: sdhci: add notifier for regulator vqmmc
[PATCH v10 12/12] mmc: sdhci-pxav3: add regulator notifier for vqmmc

changelog v1->v2:
        - remove the patch "mmc: sdhci-pxav3: fix build error"
        - update the patch 05/15 by avoid warning with return null
        - add patches 06/15 ~ 08/15
changelog v2->v3:
        - update some comments
        - add patches 09/15 ~ 11/15
changelog v3->v4:
        - update the patch 01/15 with data null check
        - add patches 12/15 ~ 15/15
changelog v4->v5:
        - drop below two patches since Johan is updating voltage switch code:
        - drop the patch "mmc: core: add new 1.8v flag for mmc"
        - drop the patch "mmc: sdhci: add mmc 1.8v signal voltage switch function"
        - drop the patch "mmc: sdhci-pxav3: add signal_voltage_switch function" which calls plat callback function
        - update the patch 07/13 with adding function get_max_clock
        - update the patch 03/13 with voltage setting
        - add patch 02/13
changelog v5->v6:
	- drop the patch "mmc: sdhci: use regulator min/max voltage range according to spec"
	- add patch 13/14
	- add patch 14/14
changelog v6->v7:
	- remove the patch "mmc: sdhci: fix null return check of regulator_get" which has been merged
	- restore the patch "mmc: sdhci: use regulator min/max voltage range according to spec"
changelog v7->v8:
	- remove the merged patch "mmc: sdhci-pxav3: controller can't get base clock"
	- remove the merged patch "mmc: host: adjust uhs timing value"
	- remove the merged patch "mmc: sdhci: solve several vmmc/vqmmc regulator issues"
	- update the patch "mmc: sdhci-pxav3: remove set_uhs_signaling function"
changelog v8->v9:
	- remove the merged patch "mmc: sdhci-pxav3: add quirks2"
	- remove the merged patch "mmc: sdhci: use regulator min/max voltage range according to spec"
	- add patch 10/10
changelog v9->v10:
	- remove the patch "mmc: sdhci: introduce signal_voltage_switch callback function"
	- add patch 6/12, 11/12, 12/12

Kevin Liu (12):

 [PATCH v10 01/12] mmc: sdhci: fix transfer mode setting bug for cmds w/o data transfer
 [PATCH v10 02/12] mmc: sdhci: refine code for clock disable/enable in set ios
 [PATCH v10 03/12] mmc: sdhci: add function to get retunig timer count
 [PATCH v10 04/12] mmc: sdhci: correct voltage support caps setting
 [PATCH v10 05/12] mmc: sdhci: clean code for SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK selected
 [PATCH v10 06/12] mmc: sdhci: remove check for CONFIG_REGULATOR
 [PATCH v10 07/12] mmc: sdhci: fix the bug that DDR50 can't work for emmc in default code
 [PATCH v10 08/12] mmc: sdhci: remove set_uhs_signaling function
 [PATCH v10 09/12] mmc: sdhci: enhance preset value function
 [PATCH v10 10/12] mmc: sdhci: keep the saved clock var up to date
 [PATCH v10 11/12] mmc: sdhci: add notifier for regulator vqmmc
 [PATCH v10 12/12] mmc: sdhci-pxav3: add regulator notifier for vqmmc

 drivers/mmc/core/sd.c                   |   17 --
 drivers/mmc/host/sdhci-pxav3.c          |   41 +-----
 drivers/mmc/host/sdhci.c                |  276 +++++++++++++++++++------------
 drivers/mmc/host/sdhci.h                |   14 ++-
 include/linux/mmc/host.h                |    1 -
 include/linux/mmc/sdhci.h               |    2 +
 include/linux/platform_data/pxa_sdhci.h |    2 +
 7 files changed, 187 insertions(+), 166 deletions(-)

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v10 01/12] mmc: sdhci: fix transfer mode setting bug for cmds w/o data transfer
  2012-12-17 11:21 [PATCH v10 00/12] mmc: sdhci: fixes and enhancements Kevin Liu
@ 2012-12-17 11:21 ` Kevin Liu
  2012-12-17 11:21 ` [PATCH v10 02/12] mmc: sdhci: refine code for clock disable/enable in set ios Kevin Liu
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Kevin Liu @ 2012-12-17 11:21 UTC (permalink / raw)
  To: linux-mmc, cjb, arindam.nath, peppe.cavallaro, ulf.hansson,
	andriy.shevchenko, prakity
  Cc: zhangfei.gao, haojian.zhuang, cxie4, keyuan.liu, Kevin Liu,
	Jialing Fu, Tim Wang

With current code, commands without data transfer like cmd5/cmd7
still use previous transfer mode setting, which may lead to error
since some bits may have been set unexpectedly.
For example, cmd5 following cmd18/cmd25 will have timeout error
since audo cmd23 has been enabled.

This bug will lead to timeout error during emmc suspend/resume
when cmd5 is called to sleep/awake emmc.
And this fix has been verified on pxa988 platform.

Reviewed By: Girish K S <girish.shivananjappa@linaro.org>
Reviewed-by: Zhangfei Gao <zhangfei.gao@marvell.com>
Signed-off-by: Jialing Fu <jlfu@marvell.com>
Signed-off-by: Tim Wang <wangtt@marvell.com>
Signed-off-by: Kevin Liu <kliu5@marvell.com>
---
 drivers/mmc/host/sdhci.c |   22 ++++++++++++++--------
 1 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 6f0bfc0..44f4ecb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -886,8 +886,21 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
 	u16 mode;
 	struct mmc_data *data = cmd->data;
 
-	if (data == NULL)
+	if (!data) {
+		if (cmd->opcode == MMC_SEND_TUNING_BLOCK ||
+			cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
+			/*
+			 * The tuning block is sent by the card to the host
+			 * controller. So we set the TRNS_READ bit in the
+			 * Transfer Mode register. This also takes care of
+			 * setting DMA Enable and Multi Block Select in the
+			 * same register to 0.
+			 */
+			sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
+		else
+			sdhci_writew(host, 0, SDHCI_TRANSFER_MODE);
 		return;
+	}
 
 	WARN_ON(!host->data);
 
@@ -1853,13 +1866,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 				     SDHCI_BLOCK_SIZE);
 		}
 
-		/*
-		 * The tuning block is sent by the card to the host controller.
-		 * So we set the TRNS_READ bit in the Transfer Mode register.
-		 * This also takes care of setting DMA Enable and Multi Block
-		 * Select in the same register to 0.
-		 */
-		sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
 
 		sdhci_send_command(host, &cmd);
 
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v10 02/12] mmc: sdhci: refine code for clock disable/enable in set ios
  2012-12-17 11:21 [PATCH v10 00/12] mmc: sdhci: fixes and enhancements Kevin Liu
  2012-12-17 11:21 ` [PATCH v10 01/12] mmc: sdhci: fix transfer mode setting bug for cmds w/o data transfer Kevin Liu
@ 2012-12-17 11:21 ` Kevin Liu
  2012-12-17 11:21 ` [PATCH v10 03/12] mmc: sdhci: add function to get retunig timer count Kevin Liu
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Kevin Liu @ 2012-12-17 11:21 UTC (permalink / raw)
  To: linux-mmc, cjb, arindam.nath, peppe.cavallaro, ulf.hansson,
	andriy.shevchenko, prakity
  Cc: zhangfei.gao, haojian.zhuang, cxie4, keyuan.liu, Kevin Liu

With preset value enabled, there are two continuous times
of clock disable/enable. They can be combined into one
to save time and make code cleaner.

Signed-off-by: Kevin Liu <kliu5@marvell.com>
---
 drivers/mmc/host/sdhci.c |   29 +++++++++--------------------
 1 files changed, 9 insertions(+), 20 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 44f4ecb..b678a08 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1452,33 +1452,22 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 				ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C;
 
 			sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
-		} else {
-			/*
-			 * According to SDHC Spec v3.00, if the Preset Value
-			 * Enable in the Host Control 2 register is set, we
-			 * need to reset SD Clock Enable before changing High
-			 * Speed Enable to avoid generating clock gliches.
-			 */
-
-			/* Reset SD Clock Enable */
-			clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
-			clk &= ~SDHCI_CLOCK_CARD_EN;
-			sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
-			sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-
-			/* Re-enable SD Clock */
-			clock = host->clock;
-			host->clock = 0;
-			sdhci_set_clock(host, clock);
 		}
 
-
 		/* Reset SD Clock Enable */
 		clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
 		clk &= ~SDHCI_CLOCK_CARD_EN;
 		sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
+		/*
+		 * According to SDHC Spec v3.00, if the Preset Value
+		 * Enable in the Host Control 2 register is set, we
+		 * need to reset SD Clock Enable before changing High
+		 * Speed Enable to avoid generating clock gliches.
+		 */
+		if (ctrl_2 & SDHCI_CTRL_PRESET_VAL_ENABLE)
+			sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+
 		if (host->ops->set_uhs_signaling)
 			host->ops->set_uhs_signaling(host, ios->timing);
 		else {
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v10 03/12] mmc: sdhci: add function to get retunig timer count
  2012-12-17 11:21 [PATCH v10 00/12] mmc: sdhci: fixes and enhancements Kevin Liu
  2012-12-17 11:21 ` [PATCH v10 01/12] mmc: sdhci: fix transfer mode setting bug for cmds w/o data transfer Kevin Liu
  2012-12-17 11:21 ` [PATCH v10 02/12] mmc: sdhci: refine code for clock disable/enable in set ios Kevin Liu
@ 2012-12-17 11:21 ` Kevin Liu
  2012-12-17 11:22 ` [PATCH v10 04/12] mmc: sdhci: correct voltage support caps setting Kevin Liu
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Kevin Liu @ 2012-12-17 11:21 UTC (permalink / raw)
  To: linux-mmc, cjb, arindam.nath, peppe.cavallaro, ulf.hansson,
	andriy.shevchenko, prakity
  Cc: zhangfei.gao, haojian.zhuang, cxie4, keyuan.liu, Kevin Liu

According to SD host spec (Capabilities Register, offset 0x40<43:40>),
if timer count for retuning return 0xF, it means get information from other source

Signed-off-by: Kevin Liu <kliu5@marvell.com>
---
 drivers/mmc/host/sdhci.c |    8 ++++++++
 drivers/mmc/host/sdhci.h |    1 +
 2 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index b678a08..66690aa 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2907,6 +2907,14 @@ int sdhci_add_host(struct sdhci_host *host)
 	/* Initial value for re-tuning timer count */
 	host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
 			      SDHCI_RETUNING_TIMER_COUNT_SHIFT;
+	if (host->tuning_count == 0xF) {
+		if (host->ops->get_tuning_count)
+			host->tuning_count =
+				host->ops->get_tuning_count(host) & 0xF;
+		else
+			pr_err("%s: Hardware doesn't specify tuning count.\n",
+				mmc_hostname(mmc));
+	}
 
 	/*
 	 * In case Re-tuning Timer is not disabled, the actual value of
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index a6d69b7..d00e273 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -282,6 +282,7 @@ struct sdhci_ops {
 	void	(*platform_resume)(struct sdhci_host *host);
 	void    (*adma_workaround)(struct sdhci_host *host, u32 intmask);
 	void	(*platform_init)(struct sdhci_host *host);
+	unsigned int    (*get_tuning_count)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v10 04/12] mmc: sdhci: correct voltage support caps setting
  2012-12-17 11:21 [PATCH v10 00/12] mmc: sdhci: fixes and enhancements Kevin Liu
                   ` (2 preceding siblings ...)
  2012-12-17 11:21 ` [PATCH v10 03/12] mmc: sdhci: add function to get retunig timer count Kevin Liu
@ 2012-12-17 11:22 ` Kevin Liu
  2012-12-17 11:22 ` [PATCH v10 05/12] mmc: sdhci: clean code for SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK selected Kevin Liu
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Kevin Liu @ 2012-12-17 11:22 UTC (permalink / raw)
  To: linux-mmc, cjb, arindam.nath, peppe.cavallaro, ulf.hansson,
	andriy.shevchenko, prakity
  Cc: zhangfei.gao, haojian.zhuang, cxie4, keyuan.liu, Kevin Liu

Correct the judgement logic.
Disable the voltage support caps which has been disabled is unreasonable

Signed-off-by: Kevin Liu <kliu5@marvell.com>
---
 drivers/mmc/host/sdhci.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 66690aa..41a007b 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2942,13 +2942,13 @@ int sdhci_add_host(struct sdhci_host *host)
 	if (host->vmmc) {
 		ret = regulator_is_supported_voltage(host->vmmc, 2700000,
 			3600000);
-		if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330)))
+		if ((ret <= 0) && (caps[0] & SDHCI_CAN_VDD_330))
 			caps[0] &= ~SDHCI_CAN_VDD_330;
-		if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_300)))
+		if ((ret <= 0) && (caps[0] & SDHCI_CAN_VDD_300))
 			caps[0] &= ~SDHCI_CAN_VDD_300;
 		ret = regulator_is_supported_voltage(host->vmmc, 1700000,
 			1950000);
-		if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_180)))
+		if ((ret <= 0) && (caps[0] & SDHCI_CAN_VDD_180))
 			caps[0] &= ~SDHCI_CAN_VDD_180;
 	}
 #endif /* CONFIG_REGULATOR */
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v10 05/12] mmc: sdhci: clean code for SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK selected
  2012-12-17 11:21 [PATCH v10 00/12] mmc: sdhci: fixes and enhancements Kevin Liu
                   ` (3 preceding siblings ...)
  2012-12-17 11:22 ` [PATCH v10 04/12] mmc: sdhci: correct voltage support caps setting Kevin Liu
@ 2012-12-17 11:22 ` Kevin Liu
  2012-12-17 11:22 ` [PATCH v10 06/12] mmc: sdhci: remove check for CONFIG_REGULATOR Kevin Liu
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Kevin Liu @ 2012-12-17 11:22 UTC (permalink / raw)
  To: linux-mmc, cjb, arindam.nath, peppe.cavallaro, ulf.hansson,
	andriy.shevchenko, prakity
  Cc: zhangfei.gao, haojian.zhuang, cxie4, keyuan.liu, Kevin Liu

If SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK is selected, getting timeout
through register or callback function is useless.

Signed-off-by: Kevin Liu <kliu5@marvell.com>
---
 drivers/mmc/host/sdhci.c |   30 +++++++++++++++---------------
 1 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 41a007b..39c81bb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2798,23 +2798,23 @@ int sdhci_add_host(struct sdhci_host *host)
 	} else
 		mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
 
-	host->timeout_clk =
-		(caps[0] & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
-	if (host->timeout_clk == 0) {
-		if (host->ops->get_timeout_clock) {
-			host->timeout_clk = host->ops->get_timeout_clock(host);
-		} else if (!(host->quirks &
-				SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
-			pr_err("%s: Hardware doesn't specify timeout clock "
-			       "frequency.\n", mmc_hostname(mmc));
-			return -ENODEV;
+	if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
+		host->timeout_clk = (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >>
+					SDHCI_TIMEOUT_CLK_SHIFT;
+		if (host->timeout_clk == 0) {
+			if (host->ops->get_timeout_clock) {
+				host->timeout_clk = host->ops->get_timeout_clock(host);
+			} else {
+				pr_err("%s: Hardware doesn't specify timeout clock "
+					"frequency.\n", mmc_hostname(mmc));
+				return -ENODEV;
+			}
 		}
-	}
-	if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
-		host->timeout_clk *= 1000;
-
-	if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
+		if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
+			host->timeout_clk *= 1000;
+	} else {
 		host->timeout_clk = mmc->f_max / 1000;
+	}
 
 	mmc->max_discard_to = (1 << 27) / host->timeout_clk;
 
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v10 06/12] mmc: sdhci: remove check for CONFIG_REGULATOR
  2012-12-17 11:21 [PATCH v10 00/12] mmc: sdhci: fixes and enhancements Kevin Liu
                   ` (4 preceding siblings ...)
  2012-12-17 11:22 ` [PATCH v10 05/12] mmc: sdhci: clean code for SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK selected Kevin Liu
@ 2012-12-17 11:22 ` Kevin Liu
  2012-12-17 11:22 ` [PATCH v10 07/12] mmc: sdhci: fix the bug that DDR50 can't work for emmc in default code Kevin Liu
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Kevin Liu @ 2012-12-17 11:22 UTC (permalink / raw)
  To: linux-mmc, cjb, arindam.nath, peppe.cavallaro, ulf.hansson,
	andriy.shevchenko, prakity
  Cc: zhangfei.gao, haojian.zhuang, cxie4, keyuan.liu, Kevin Liu

host->vmmc will be NULL if CONFIG_REGULATOR is not defined,
so the check can be removed.

Signed-off-by: Kevin Liu <kliu5@marvell.com>
---
 drivers/mmc/host/sdhci.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 39c81bb..98b2a2a 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2938,7 +2938,6 @@ int sdhci_add_host(struct sdhci_host *host)
 		}
 	}
 
-#ifdef CONFIG_REGULATOR
 	if (host->vmmc) {
 		ret = regulator_is_supported_voltage(host->vmmc, 2700000,
 			3600000);
@@ -2951,7 +2950,6 @@ int sdhci_add_host(struct sdhci_host *host)
 		if ((ret <= 0) && (caps[0] & SDHCI_CAN_VDD_180))
 			caps[0] &= ~SDHCI_CAN_VDD_180;
 	}
-#endif /* CONFIG_REGULATOR */
 
 	/*
 	 * According to SD Host Controller spec v3.00, if the Host System
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v10 07/12] mmc: sdhci: fix the bug that DDR50 can't work for emmc in default code
  2012-12-17 11:21 [PATCH v10 00/12] mmc: sdhci: fixes and enhancements Kevin Liu
                   ` (5 preceding siblings ...)
  2012-12-17 11:22 ` [PATCH v10 06/12] mmc: sdhci: remove check for CONFIG_REGULATOR Kevin Liu
@ 2012-12-17 11:22 ` Kevin Liu
  2012-12-17 11:22 ` [PATCH v10 08/12] mmc: sdhci: remove set_uhs_signaling function Kevin Liu
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Kevin Liu @ 2012-12-17 11:22 UTC (permalink / raw)
  To: linux-mmc, cjb, arindam.nath, peppe.cavallaro, ulf.hansson,
	andriy.shevchenko, prakity
  Cc: zhangfei.gao, haojian.zhuang, cxie4, keyuan.liu, Kevin Liu

According to SD host controller spec (Host Control 2 Register, offset 0x3E<3:0>),
1.8v signaling must be enabled for UHS-I modes. Otherwise all UHS-I modes
will NOT take effect.
For both sd and sdio card with UHS-I enabled, 1.8v signaling is enabled
in mmc_set_signal_voltage. But emmc with DDR50 won't change the voltage.
So 1.8v signal enabling is missed by default for emmc with DDR50.
And DDR50 will NOT take effect at all in this case.
Of course we can added this operation in callback function set_uhs_signaling.
In fact only sdhci-pxav3.c did this. But we should fix this in sdhci.c
since the spec required this explicitly. Then the callback function can be removed.
This patch enable the 1.8v signaling for mmc DDR50 mode in sdhci.c.

Below is more infomation from spec:
In JEDEC spec, there are two emmc device types which support DDR50.
One type can work under signal 1.2v while the other type work under
signal 1.8v or 3v. So current code just keep 3v for the second device
type.

But in SD host spec, 1.8v signal must be enabled for all UHS-I modes
taking effect. So the fact is, if using SD host to work with emmc chip,
then 1.8v signal must be selected in order to enable DDR50.
Current code missed this.

Because DDR50 shall can work under both signal 1.8v and 3v according
to JEDEC spec,  So always switching to 1.8v in mmc core code is
unreasonable. It's the SD host controller's requirement that 1.8v
signal must be enabled for DDR50, which conflict with JEDEC spec.
So correct this in host driver.

Signed-off-by: Kevin Liu <kliu5@marvell.com>
---
 drivers/mmc/host/sdhci.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 98b2a2a..4ef94a5 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1484,8 +1484,15 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 				ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
 			else if (ios->timing == MMC_TIMING_UHS_SDR104)
 				ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
-			else if (ios->timing == MMC_TIMING_UHS_DDR50)
+			else if (ios->timing == MMC_TIMING_UHS_DDR50) {
+				struct mmc_card	*card;
+
 				ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+				card = container_of(&(host->mmc),
+					struct mmc_card, host);
+				if (mmc_card_mmc(card))
+					ctrl_2 |= SDHCI_CTRL_VDD_180;
+			}
 			sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
 		}
 
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v10 08/12] mmc: sdhci: remove set_uhs_signaling function
  2012-12-17 11:21 [PATCH v10 00/12] mmc: sdhci: fixes and enhancements Kevin Liu
                   ` (6 preceding siblings ...)
  2012-12-17 11:22 ` [PATCH v10 07/12] mmc: sdhci: fix the bug that DDR50 can't work for emmc in default code Kevin Liu
@ 2012-12-17 11:22 ` Kevin Liu
  2012-12-17 11:22 ` [PATCH v10 09/12] mmc: sdhci: enhance preset value function Kevin Liu
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Kevin Liu @ 2012-12-17 11:22 UTC (permalink / raw)
  To: linux-mmc, cjb, arindam.nath, peppe.cavallaro, ulf.hansson,
	andriy.shevchenko, prakity
  Cc: zhangfei.gao, haojian.zhuang, cxie4, keyuan.liu, Kevin Liu

Because default way can cover all cases so no need to implement this.

Acked-by: Zhangfei Gao <zhangfei.gao@marvell.com>
Signed-off-by: Kevin Liu <kliu5@marvell.com>
---
 drivers/mmc/host/sdhci-pxav3.c |   39 ---------------------------------
 drivers/mmc/host/sdhci.c       |   46 ++++++++++++++++++---------------------
 drivers/mmc/host/sdhci.h       |    1 -
 3 files changed, 21 insertions(+), 65 deletions(-)

diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index fad0966..a308598 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -125,44 +125,6 @@ static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode)
 	pxa->power_mode = power_mode;
 }
 
-static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
-{
-	u16 ctrl_2;
-
-	/*
-	 * Set V18_EN -- UHS modes do not work without this.
-	 * does not change signaling voltage
-	 */
-	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-
-	/* Select Bus Speed Mode for host */
-	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
-	switch (uhs) {
-	case MMC_TIMING_UHS_SDR12:
-		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
-		break;
-	case MMC_TIMING_UHS_SDR25:
-		ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
-		break;
-	case MMC_TIMING_UHS_SDR50:
-		ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180;
-		break;
-	case MMC_TIMING_UHS_SDR104:
-		ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180;
-		break;
-	case MMC_TIMING_UHS_DDR50:
-		ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180;
-		break;
-	}
-
-	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
-	dev_dbg(mmc_dev(host->mmc),
-		"%s uhs = %d, ctrl_2 = %04X\n",
-		__func__, uhs, ctrl_2);
-
-	return 0;
-}
-
 static u32 pxav3_get_max_clock(struct sdhci_host *host)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -172,7 +134,6 @@ static u32 pxav3_get_max_clock(struct sdhci_host *host)
 
 static struct sdhci_ops pxav3_sdhci_ops = {
 	.platform_reset_exit = pxav3_set_private_registers,
-	.set_uhs_signaling = pxav3_set_uhs_signaling,
 	.platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
 	.get_max_clock = pxav3_get_max_clock,
 };
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 4ef94a5..c0380a4 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1468,33 +1468,29 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 		if (ctrl_2 & SDHCI_CTRL_PRESET_VAL_ENABLE)
 			sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
-		if (host->ops->set_uhs_signaling)
-			host->ops->set_uhs_signaling(host, ios->timing);
-		else {
-			ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-			/* Select Bus Speed Mode for host */
-			ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
-			if (ios->timing == MMC_TIMING_MMC_HS200)
-				ctrl_2 |= SDHCI_CTRL_HS_SDR200;
-			else if (ios->timing == MMC_TIMING_UHS_SDR12)
-				ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
-			else if (ios->timing == MMC_TIMING_UHS_SDR25)
-				ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
-			else if (ios->timing == MMC_TIMING_UHS_SDR50)
-				ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
-			else if (ios->timing == MMC_TIMING_UHS_SDR104)
-				ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
-			else if (ios->timing == MMC_TIMING_UHS_DDR50) {
-				struct mmc_card	*card;
-
-				ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
-				card = container_of(&(host->mmc),
+		ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+		/* Select Bus Speed Mode for host */
+		ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+		if (ios->timing == MMC_TIMING_MMC_HS200)
+			ctrl_2 |= SDHCI_CTRL_HS_SDR200;
+		else if (ios->timing == MMC_TIMING_UHS_SDR12)
+			ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+		else if (ios->timing == MMC_TIMING_UHS_SDR25)
+			ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+		else if (ios->timing == MMC_TIMING_UHS_SDR50)
+			ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
+		else if (ios->timing == MMC_TIMING_UHS_SDR104)
+			ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+		else if (ios->timing == MMC_TIMING_UHS_DDR50) {
+			struct mmc_card	*card;
+
+			ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+			card = container_of(&(host->mmc),
 					struct mmc_card, host);
-				if (mmc_card_mmc(card))
-					ctrl_2 |= SDHCI_CTRL_VDD_180;
-			}
-			sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+			if (mmc_card_mmc(card))
+				ctrl_2 |= SDHCI_CTRL_VDD_180;
 		}
+		sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
 
 		/* Re-enable SD Clock */
 		clock = host->clock;
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index d00e273..e0c9120 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -276,7 +276,6 @@ struct sdhci_ops {
 	unsigned int    (*get_ro)(struct sdhci_host *host);
 	void	(*platform_reset_enter)(struct sdhci_host *host, u8 mask);
 	void	(*platform_reset_exit)(struct sdhci_host *host, u8 mask);
-	int	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
 	void	(*hw_reset)(struct sdhci_host *host);
 	void	(*platform_suspend)(struct sdhci_host *host);
 	void	(*platform_resume)(struct sdhci_host *host);
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v10 09/12] mmc: sdhci: enhance preset value function
  2012-12-17 11:21 [PATCH v10 00/12] mmc: sdhci: fixes and enhancements Kevin Liu
                   ` (7 preceding siblings ...)
  2012-12-17 11:22 ` [PATCH v10 08/12] mmc: sdhci: remove set_uhs_signaling function Kevin Liu
@ 2012-12-17 11:22 ` Kevin Liu
  2012-12-17 21:05   ` Ulf Hansson
  2012-12-17 11:22 ` [PATCH v10 10/12] mmc: sdhci: keep the saved clock var up to date Kevin Liu
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 14+ messages in thread
From: Kevin Liu @ 2012-12-17 11:22 UTC (permalink / raw)
  To: linux-mmc, cjb, arindam.nath, peppe.cavallaro, ulf.hansson,
	andriy.shevchenko, prakity
  Cc: zhangfei.gao, haojian.zhuang, cxie4, keyuan.liu, Kevin Liu

Preset value support was added by 4d55c5a1.

But preset value is enabled after setting clock finished,
which means the clock is still set by driver firstly and
then switch to preset value at this point. So the
driver setting beforehand is useless and unnecessary.
What's more, driver is still using the old value which may
differ from the preset one. The better way is enable preset
value just after switch to UHS mode so the preset value can
be used immediately. So move preset value enable from
mmc_sd_init_card to sdhci_set_ios which will be called during
set timing.

And preset value is disabled at the begining of mmc_attach_sd.
It's a bit late since low freq should be set in mmc_power_up.
So move preset value disable to sdhci_set_ios which will be
called during power up.

Also update host->clock and ios->drv_type according to the
preset value.

This patch has been verified on sdhci-pxav3 platform with
both preset enabled and disabled.

Signed-off-by: Kevin Liu <kliu5@marvell.com>
---
 drivers/mmc/core/sd.c     |   17 ------
 drivers/mmc/host/sdhci.c  |  128 +++++++++++++++++++++++++++++++--------------
 drivers/mmc/host/sdhci.h  |   12 ++++
 include/linux/mmc/host.h  |    1 -
 include/linux/mmc/sdhci.h |    1 +
 5 files changed, 101 insertions(+), 58 deletions(-)

diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 74972c2..3dafb54 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -960,16 +960,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 
 		/* Card is an ultra-high-speed card */
 		mmc_card_set_uhs(card);
-
-		/*
-		 * Since initialization is now complete, enable preset
-		 * value registers for UHS-I cards.
-		 */
-		if (host->ops->enable_preset_value) {
-			mmc_host_clk_hold(card->host);
-			host->ops->enable_preset_value(host, true);
-			mmc_host_clk_release(card->host);
-		}
 	} else {
 		/*
 		 * Attempt to change to high-speed (if supported)
@@ -1148,13 +1138,6 @@ int mmc_attach_sd(struct mmc_host *host)
 	BUG_ON(!host);
 	WARN_ON(!host->claimed);
 
-	/* Disable preset value enable if already set since last time */
-	if (host->ops->enable_preset_value) {
-		mmc_host_clk_hold(host);
-		host->ops->enable_preset_value(host, false);
-		mmc_host_clk_release(host);
-	}
-
 	err = mmc_send_app_op_cond(host, 0, &ocr);
 	if (err)
 		return err;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index c0380a4..6699497 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -53,6 +53,7 @@ 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, u32 opcode);
 static void sdhci_tuning_timer(unsigned long data);
+static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
 
 #ifdef CONFIG_PM_RUNTIME
 static int sdhci_runtime_pm_get(struct sdhci_host *host);
@@ -1095,6 +1096,34 @@ static void sdhci_finish_command(struct sdhci_host *host)
 	}
 }
 
+static u16 sdhci_get_preset_value(struct sdhci_host *host)
+{
+	u16 ctrl, preset = 0;
+
+	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+	switch (ctrl & SDHCI_CTRL_UHS_MASK) {
+	case SDHCI_CTRL_UHS_SDR12:
+		preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12);
+		break;
+	case SDHCI_CTRL_UHS_SDR25:
+		preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR25);
+		break;
+	case SDHCI_CTRL_UHS_SDR50:
+		preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR50);
+		break;
+	case SDHCI_CTRL_UHS_SDR104:
+		preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104);
+		break;
+	case SDHCI_CTRL_UHS_DDR50:
+		preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);
+		break;
+	default:
+		BUG();
+	}
+	return preset;
+}
+
 static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 {
 	int div = 0; /* Initialized for compiler warning */
@@ -1119,35 +1148,45 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 		goto out;
 
 	if (host->version >= SDHCI_SPEC_300) {
+		if (sdhci_readw(host, SDHCI_HOST_CONTROL2) &
+			SDHCI_CTRL_PRESET_VAL_ENABLE) {
+			u16 pre_val;
+
+			clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+			pre_val = sdhci_get_preset_value(host);
+			div = (pre_val & SDHCI_PRESET_SDCLK_FREQ_MASK)
+				>> SDHCI_PRESET_SDCLK_FREQ_SHIFT;
+			if (host->clk_mul &&
+				(pre_val & SDHCI_PRESET_CLKGEN_SEL_MASK)) {
+				clk = SDHCI_PROG_CLOCK_MODE;
+				real_div = div + 1;
+				clk_mul = host->clk_mul;
+			} else {
+				if (div == 0)
+					real_div = 1;
+				else
+					real_div = div << 1;
+			}
+			goto preset;
+		}
 		/*
 		 * Check if the Host Controller supports Programmable Clock
 		 * Mode.
 		 */
 		if (host->clk_mul) {
-			u16 ctrl;
-
+			for (div = 1; div <= 1024; div++) {
+				if (((host->max_clk * host->clk_mul) /
+							div) <= clock)
+					break;
+			}
 			/*
-			 * We need to figure out whether the Host Driver needs
-			 * to select Programmable Clock Mode, or the value can
-			 * be set automatically by the Host Controller based on
-			 * the Preset Value registers.
+			 * Set Programmable Clock Mode in the Clock
+			 * Control register.
 			 */
-			ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-			if (!(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
-				for (div = 1; div <= 1024; div++) {
-					if (((host->max_clk * host->clk_mul) /
-					      div) <= clock)
-						break;
-				}
-				/*
-				 * Set Programmable Clock Mode in the Clock
-				 * Control register.
-				 */
-				clk = SDHCI_PROG_CLOCK_MODE;
-				real_div = div;
-				clk_mul = host->clk_mul;
-				div--;
-			}
+			clk = SDHCI_PROG_CLOCK_MODE;
+			real_div = div;
+			clk_mul = host->clk_mul;
+			div--;
 		} else {
 			/* Version 3.00 divisors must be a multiple of 2. */
 			if (host->max_clk <= clock)
@@ -1172,6 +1211,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 		div >>= 1;
 	}
 
+preset:
 	if (real_div)
 		host->mmc->actual_clock = (host->max_clk * clk_mul) / real_div;
 
@@ -1377,6 +1417,10 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 		sdhci_reinit(host);
 	}
 
+	if (host->version >= SDHCI_SPEC_300 &&
+		(ios->power_mode == MMC_POWER_UP))
+		sdhci_enable_preset_value(host, false);
+
 	sdhci_set_clock(host, ios->clock);
 
 	if (ios->power_mode == MMC_POWER_OFF)
@@ -1492,6 +1536,20 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 		}
 		sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
 
+		if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
+				((ios->timing == MMC_TIMING_UHS_SDR12) ||
+				 (ios->timing == MMC_TIMING_UHS_SDR25) ||
+				 (ios->timing == MMC_TIMING_UHS_SDR50) ||
+				 (ios->timing == MMC_TIMING_UHS_SDR104) ||
+				 (ios->timing == MMC_TIMING_UHS_DDR50))) {
+			u16 preset;
+
+			sdhci_enable_preset_value(host, true);
+			preset = sdhci_get_preset_value(host);
+			ios->drv_type = (preset & SDHCI_PRESET_DRV_MASK)
+				>> SDHCI_PRESET_DRV_SHIFT;
+		}
+
 		/* Re-enable SD Clock */
 		clock = host->clock;
 		host->clock = 0;
@@ -1953,17 +2011,15 @@ out:
 	return err;
 }
 
-static void sdhci_do_enable_preset_value(struct sdhci_host *host, bool enable)
+
+static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
 {
 	u16 ctrl;
-	unsigned long flags;
 
 	/* Host Controller v3.00 defines preset value registers */
 	if (host->version < SDHCI_SPEC_300)
 		return;
 
-	spin_lock_irqsave(&host->lock, flags);
-
 	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 
 	/*
@@ -1979,17 +2035,6 @@ static void sdhci_do_enable_preset_value(struct sdhci_host *host, bool enable)
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 		host->flags &= ~SDHCI_PV_ENABLED;
 	}
-
-	spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
-{
-	struct sdhci_host *host = mmc_priv(mmc);
-
-	sdhci_runtime_pm_get(host);
-	sdhci_do_enable_preset_value(host, enable);
-	sdhci_runtime_pm_put(host);
 }
 
 static void sdhci_card_event(struct mmc_host *mmc)
@@ -2025,7 +2070,6 @@ static const struct mmc_host_ops sdhci_ops = {
 	.enable_sdio_irq = sdhci_enable_sdio_irq,
 	.start_signal_voltage_switch	= sdhci_start_signal_voltage_switch,
 	.execute_tuning			= sdhci_execute_tuning,
-	.enable_preset_value		= sdhci_enable_preset_value,
 	.card_event			= sdhci_card_event,
 };
 
@@ -2598,8 +2642,12 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
 	sdhci_do_set_ios(host, &host->mmc->ios);
 
 	sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
-	if (host_flags & SDHCI_PV_ENABLED)
-		sdhci_do_enable_preset_value(host, true);
+	if ((host_flags & SDHCI_PV_ENABLED) &&
+		!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
+		spin_lock_irqsave(&host->lock, flags);
+		sdhci_enable_preset_value(host, true);
+		spin_unlock_irqrestore(&host->lock, flags);
+	}
 
 	/* Set the re-tuning expiration flag */
 	if (host->flags & SDHCI_USING_RETUNING_TIMER)
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index e0c9120..df13303 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -229,6 +229,18 @@
 
 /* 60-FB reserved */
 
+#define SDHCI_PRESET_FOR_SDR12 0x66
+#define SDHCI_PRESET_FOR_SDR25 0x68
+#define SDHCI_PRESET_FOR_SDR50 0x6A
+#define SDHCI_PRESET_FOR_SDR104        0x6C
+#define SDHCI_PRESET_FOR_DDR50 0x6E
+#define SDHCI_PRESET_DRV_MASK  0xC000
+#define SDHCI_PRESET_DRV_SHIFT  14
+#define SDHCI_PRESET_CLKGEN_SEL_MASK   0x400
+#define SDHCI_PRESET_CLKGEN_SEL_SHIFT	10
+#define SDHCI_PRESET_SDCLK_FREQ_MASK   0x3FF
+#define SDHCI_PRESET_SDCLK_FREQ_SHIFT	0
+
 #define SDHCI_SLOT_INT_STATUS	0xFC
 
 #define SDHCI_HOST_VERSION	0xFE
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 61a10c1..52a55b6 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -133,7 +133,6 @@ struct mmc_host_ops {
 
 	/* 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);
 	void	(*card_event)(struct mmc_host *host);
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 4bbc330..b838ffc 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -94,6 +94,7 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_HOST_NO_CMD23			(1<<1)
 /* The system physically doesn't support 1.8v, even if the host does */
 #define SDHCI_QUIRK2_NO_1_8_V				(1<<2)
+#define SDHCI_QUIRK2_PRESET_VALUE_BROKEN		(1<<3)
 
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v10 10/12] mmc: sdhci: keep the saved clock var up to date
  2012-12-17 11:21 [PATCH v10 00/12] mmc: sdhci: fixes and enhancements Kevin Liu
                   ` (8 preceding siblings ...)
  2012-12-17 11:22 ` [PATCH v10 09/12] mmc: sdhci: enhance preset value function Kevin Liu
@ 2012-12-17 11:22 ` Kevin Liu
  2012-12-17 11:22 ` [PATCH v10 11/12] mmc: sdhci: add notifier for regulator vqmmc Kevin Liu
  2012-12-17 11:22 ` [PATCH v10 12/12] mmc: sdhci-pxav3: add regulator notifier for vqmmc Kevin Liu
  11 siblings, 0 replies; 14+ messages in thread
From: Kevin Liu @ 2012-12-17 11:22 UTC (permalink / raw)
  To: linux-mmc, cjb, arindam.nath, peppe.cavallaro, ulf.hansson,
	andriy.shevchenko, prakity
  Cc: zhangfei.gao, haojian.zhuang, cxie4, keyuan.liu, Kevin Liu, Bin Wang

The clock rate set to the sdh controller may not exactly as requested
by the mmc core, this patch make the clock rate saved in the mmc_ios
and sdhci_host updated with the actual setting as in the controller. Thus
"/sys/kernel/debug/mmcx/ios" and card detect prints can show the correct
clock rate.
Otherwise, mmc power class may be set to wrong value with wrong ios.clock

Signed-off-by: Bin Wang <binw@marvell.com>
Signed-off-by: Kevin Liu <kliu5@marvell.com>
---
 drivers/mmc/host/sdhci.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 6699497..7084a1c 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1239,7 +1239,10 @@ preset:
 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
 out:
-	host->clock = clock;
+	if (real_div)
+		host->clock = host->mmc->actual_clock;
+	else
+		host->clock = clock;
 }
 
 static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
@@ -1422,6 +1425,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 		sdhci_enable_preset_value(host, false);
 
 	sdhci_set_clock(host, ios->clock);
+	ios->clock = host->clock;
 
 	if (ios->power_mode == MMC_POWER_OFF)
 		vdd_bit = sdhci_set_power(host, -1);
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v10 11/12] mmc: sdhci: add notifier for regulator vqmmc
  2012-12-17 11:21 [PATCH v10 00/12] mmc: sdhci: fixes and enhancements Kevin Liu
                   ` (9 preceding siblings ...)
  2012-12-17 11:22 ` [PATCH v10 10/12] mmc: sdhci: keep the saved clock var up to date Kevin Liu
@ 2012-12-17 11:22 ` Kevin Liu
  2012-12-17 11:22 ` [PATCH v10 12/12] mmc: sdhci-pxav3: add regulator notifier for vqmmc Kevin Liu
  11 siblings, 0 replies; 14+ messages in thread
From: Kevin Liu @ 2012-12-17 11:22 UTC (permalink / raw)
  To: linux-mmc, cjb, arindam.nath, peppe.cavallaro, ulf.hansson,
	andriy.shevchenko, prakity
  Cc: zhangfei.gao, haojian.zhuang, cxie4, keyuan.liu, Kevin Liu,
	Philip Rakity

Some soc/platform need specific handling for signal voltage
switch. For example, mmp2/mmp3 need to set the AIB IO domain
control register accordingly.
Use regulator notifier to do this.

Signed-off-by: Philip Rakity <prakity@marvell.com>
Signed-off-by: Kevin Liu <kliu5@marvell.com>
---
 drivers/mmc/host/sdhci.c  |    4 ++++
 include/linux/mmc/sdhci.h |    1 +
 2 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 7084a1c..4aa2fb8 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2923,6 +2923,8 @@ int sdhci_add_host(struct sdhci_host *host)
 			caps[1] &= ~(SDHCI_SUPPORT_SDR104 |
 					SDHCI_SUPPORT_SDR50 |
 					SDHCI_SUPPORT_DDR50);
+		if (host->nb_vqmmc)
+			regulator_register_notifier(host->vqmmc, host->nb_vqmmc);
 	}
 
 	if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)
@@ -3250,6 +3252,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
 	}
 
 	if (host->vqmmc) {
+		if (host->nb_vqmmc)
+			regulator_unregister_notifier(host->vqmmc, host->nb_vqmmc);
 		regulator_disable(host->vqmmc);
 		regulator_put(host->vqmmc);
 	}
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index b838ffc..dbb0a7e 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -103,6 +103,7 @@ struct sdhci_host {
 
 	struct regulator *vmmc;		/* Power regulator (vmmc) */
 	struct regulator *vqmmc;	/* Signaling regulator (vccq) */
+	struct notifier_block	*nb_vqmmc;	/* Regulator notifier for vccq */
 
 	/* Internal data */
 	struct mmc_host *mmc;	/* MMC structure */
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v10 12/12] mmc: sdhci-pxav3: add regulator notifier for vqmmc
  2012-12-17 11:21 [PATCH v10 00/12] mmc: sdhci: fixes and enhancements Kevin Liu
                   ` (10 preceding siblings ...)
  2012-12-17 11:22 ` [PATCH v10 11/12] mmc: sdhci: add notifier for regulator vqmmc Kevin Liu
@ 2012-12-17 11:22 ` Kevin Liu
  11 siblings, 0 replies; 14+ messages in thread
From: Kevin Liu @ 2012-12-17 11:22 UTC (permalink / raw)
  To: linux-mmc, cjb, arindam.nath, peppe.cavallaro, ulf.hansson,
	andriy.shevchenko, prakity
  Cc: zhangfei.gao, haojian.zhuang, cxie4, keyuan.liu, Kevin Liu

Signed-off-by: Kevin Liu <kliu5@marvell.com>
---
 drivers/mmc/host/sdhci-pxav3.c          |    2 ++
 include/linux/platform_data/pxa_sdhci.h |    2 ++
 2 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index a308598..d2fb16e 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -258,6 +258,8 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
 				goto err_cd_req;
 			}
 		}
+		if (pdata->nb_vqmmc)
+			host->nb_vqmmc = pdata->nb_vqmmc;
 	}
 
 	host->ops = &pxav3_sdhci_ops;
diff --git a/include/linux/platform_data/pxa_sdhci.h b/include/linux/platform_data/pxa_sdhci.h
index 27d3156..86e027b 100644
--- a/include/linux/platform_data/pxa_sdhci.h
+++ b/include/linux/platform_data/pxa_sdhci.h
@@ -40,6 +40,7 @@
  * @quirks: quirks of platfrom
  * @quirks2: quirks2 of platfrom
  * @pm_caps: pm_caps of platfrom
+ * @nb_vqmmc: regulator notifier for vqmmc
  */
 struct sdhci_pxa_platdata {
 	unsigned int	flags;
@@ -54,6 +55,7 @@ struct sdhci_pxa_platdata {
 	unsigned int	quirks;
 	unsigned int	quirks2;
 	unsigned int	pm_caps;
+	struct notifier_block	*nb_vqmmc;
 };
 
 struct sdhci_pxa {
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH v10 09/12] mmc: sdhci: enhance preset value function
  2012-12-17 11:22 ` [PATCH v10 09/12] mmc: sdhci: enhance preset value function Kevin Liu
@ 2012-12-17 21:05   ` Ulf Hansson
  0 siblings, 0 replies; 14+ messages in thread
From: Ulf Hansson @ 2012-12-17 21:05 UTC (permalink / raw)
  To: Kevin Liu
  Cc: linux-mmc, cjb, arindam.nath, peppe.cavallaro, andriy.shevchenko,
	prakity, zhangfei.gao, haojian.zhuang, cxie4, keyuan.liu

On 17 December 2012 12:22, Kevin Liu <kliu5@marvell.com> wrote:
> Preset value support was added by 4d55c5a1.
>
> But preset value is enabled after setting clock finished,
> which means the clock is still set by driver firstly and
> then switch to preset value at this point. So the
> driver setting beforehand is useless and unnecessary.
> What's more, driver is still using the old value which may
> differ from the preset one. The better way is enable preset
> value just after switch to UHS mode so the preset value can
> be used immediately. So move preset value enable from
> mmc_sd_init_card to sdhci_set_ios which will be called during
> set timing.
>
> And preset value is disabled at the begining of mmc_attach_sd.
> It's a bit late since low freq should be set in mmc_power_up.
> So move preset value disable to sdhci_set_ios which will be
> called during power up.
>
> Also update host->clock and ios->drv_type according to the
> preset value.
>
> This patch has been verified on sdhci-pxav3 platform with
> both preset enabled and disabled.
>
> Signed-off-by: Kevin Liu <kliu5@marvell.com>
> ---
>  drivers/mmc/core/sd.c     |   17 ------
>  drivers/mmc/host/sdhci.c  |  128 +++++++++++++++++++++++++++++++--------------
>  drivers/mmc/host/sdhci.h  |   12 ++++
>  include/linux/mmc/host.h  |    1 -
>  include/linux/mmc/sdhci.h |    1 +
>  5 files changed, 101 insertions(+), 58 deletions(-)
>
> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> index 74972c2..3dafb54 100644
> --- a/drivers/mmc/core/sd.c
> +++ b/drivers/mmc/core/sd.c
> @@ -960,16 +960,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
>
>                 /* Card is an ultra-high-speed card */
>                 mmc_card_set_uhs(card);
> -
> -               /*
> -                * Since initialization is now complete, enable preset
> -                * value registers for UHS-I cards.
> -                */
> -               if (host->ops->enable_preset_value) {
> -                       mmc_host_clk_hold(card->host);
> -                       host->ops->enable_preset_value(host, true);
> -                       mmc_host_clk_release(card->host);
> -               }
>         } else {
>                 /*
>                  * Attempt to change to high-speed (if supported)
> @@ -1148,13 +1138,6 @@ int mmc_attach_sd(struct mmc_host *host)
>         BUG_ON(!host);
>         WARN_ON(!host->claimed);
>
> -       /* Disable preset value enable if already set since last time */
> -       if (host->ops->enable_preset_value) {
> -               mmc_host_clk_hold(host);
> -               host->ops->enable_preset_value(host, false);
> -               mmc_host_clk_release(host);
> -       }
> -
>         err = mmc_send_app_op_cond(host, 0, &ocr);
>         if (err)
>                 return err;
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index c0380a4..6699497 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -53,6 +53,7 @@ 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, u32 opcode);
>  static void sdhci_tuning_timer(unsigned long data);
> +static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
>
>  #ifdef CONFIG_PM_RUNTIME
>  static int sdhci_runtime_pm_get(struct sdhci_host *host);
> @@ -1095,6 +1096,34 @@ static void sdhci_finish_command(struct sdhci_host *host)
>         }
>  }
>
> +static u16 sdhci_get_preset_value(struct sdhci_host *host)
> +{
> +       u16 ctrl, preset = 0;
> +
> +       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> +
> +       switch (ctrl & SDHCI_CTRL_UHS_MASK) {
> +       case SDHCI_CTRL_UHS_SDR12:
> +               preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12);
> +               break;
> +       case SDHCI_CTRL_UHS_SDR25:
> +               preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR25);
> +               break;
> +       case SDHCI_CTRL_UHS_SDR50:
> +               preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR50);
> +               break;
> +       case SDHCI_CTRL_UHS_SDR104:
> +               preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104);
> +               break;
> +       case SDHCI_CTRL_UHS_DDR50:
> +               preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);
> +               break;
> +       default:
> +               BUG();
> +       }
> +       return preset;
> +}
> +
>  static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
>  {
>         int div = 0; /* Initialized for compiler warning */
> @@ -1119,35 +1148,45 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
>                 goto out;
>
>         if (host->version >= SDHCI_SPEC_300) {
> +               if (sdhci_readw(host, SDHCI_HOST_CONTROL2) &
> +                       SDHCI_CTRL_PRESET_VAL_ENABLE) {
> +                       u16 pre_val;
> +
> +                       clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> +                       pre_val = sdhci_get_preset_value(host);
> +                       div = (pre_val & SDHCI_PRESET_SDCLK_FREQ_MASK)
> +                               >> SDHCI_PRESET_SDCLK_FREQ_SHIFT;
> +                       if (host->clk_mul &&
> +                               (pre_val & SDHCI_PRESET_CLKGEN_SEL_MASK)) {
> +                               clk = SDHCI_PROG_CLOCK_MODE;
> +                               real_div = div + 1;
> +                               clk_mul = host->clk_mul;
> +                       } else {
> +                               if (div == 0)
> +                                       real_div = 1;
> +                               else
> +                                       real_div = div << 1;
> +                       }
> +                       goto preset;
> +               }
>                 /*
>                  * Check if the Host Controller supports Programmable Clock
>                  * Mode.
>                  */
>                 if (host->clk_mul) {
> -                       u16 ctrl;
> -
> +                       for (div = 1; div <= 1024; div++) {
> +                               if (((host->max_clk * host->clk_mul) /
> +                                                       div) <= clock)
> +                                       break;
> +                       }
>                         /*
> -                        * We need to figure out whether the Host Driver needs
> -                        * to select Programmable Clock Mode, or the value can
> -                        * be set automatically by the Host Controller based on
> -                        * the Preset Value registers.
> +                        * Set Programmable Clock Mode in the Clock
> +                        * Control register.
>                          */
> -                       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> -                       if (!(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
> -                               for (div = 1; div <= 1024; div++) {
> -                                       if (((host->max_clk * host->clk_mul) /
> -                                             div) <= clock)
> -                                               break;
> -                               }
> -                               /*
> -                                * Set Programmable Clock Mode in the Clock
> -                                * Control register.
> -                                */
> -                               clk = SDHCI_PROG_CLOCK_MODE;
> -                               real_div = div;
> -                               clk_mul = host->clk_mul;
> -                               div--;
> -                       }
> +                       clk = SDHCI_PROG_CLOCK_MODE;
> +                       real_div = div;
> +                       clk_mul = host->clk_mul;
> +                       div--;
>                 } else {
>                         /* Version 3.00 divisors must be a multiple of 2. */
>                         if (host->max_clk <= clock)
> @@ -1172,6 +1211,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
>                 div >>= 1;
>         }
>
> +preset:
>         if (real_div)
>                 host->mmc->actual_clock = (host->max_clk * clk_mul) / real_div;
>
> @@ -1377,6 +1417,10 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
>                 sdhci_reinit(host);
>         }
>
> +       if (host->version >= SDHCI_SPEC_300 &&
> +               (ios->power_mode == MMC_POWER_UP))
> +               sdhci_enable_preset_value(host, false);
> +
>         sdhci_set_clock(host, ios->clock);
>
>         if (ios->power_mode == MMC_POWER_OFF)
> @@ -1492,6 +1536,20 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
>                 }
>                 sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
>
> +               if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
> +                               ((ios->timing == MMC_TIMING_UHS_SDR12) ||
> +                                (ios->timing == MMC_TIMING_UHS_SDR25) ||
> +                                (ios->timing == MMC_TIMING_UHS_SDR50) ||
> +                                (ios->timing == MMC_TIMING_UHS_SDR104) ||
> +                                (ios->timing == MMC_TIMING_UHS_DDR50))) {
> +                       u16 preset;
> +
> +                       sdhci_enable_preset_value(host, true);
> +                       preset = sdhci_get_preset_value(host);
> +                       ios->drv_type = (preset & SDHCI_PRESET_DRV_MASK)
> +                               >> SDHCI_PRESET_DRV_SHIFT;
> +               }
> +
>                 /* Re-enable SD Clock */
>                 clock = host->clock;
>                 host->clock = 0;
> @@ -1953,17 +2011,15 @@ out:
>         return err;
>  }
>
> -static void sdhci_do_enable_preset_value(struct sdhci_host *host, bool enable)
> +
> +static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
>  {
>         u16 ctrl;
> -       unsigned long flags;
>
>         /* Host Controller v3.00 defines preset value registers */
>         if (host->version < SDHCI_SPEC_300)
>                 return;
>
> -       spin_lock_irqsave(&host->lock, flags);
> -
>         ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
>
>         /*
> @@ -1979,17 +2035,6 @@ static void sdhci_do_enable_preset_value(struct sdhci_host *host, bool enable)
>                 sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
>                 host->flags &= ~SDHCI_PV_ENABLED;
>         }
> -
> -       spin_unlock_irqrestore(&host->lock, flags);
> -}
> -
> -static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
> -{
> -       struct sdhci_host *host = mmc_priv(mmc);
> -
> -       sdhci_runtime_pm_get(host);
> -       sdhci_do_enable_preset_value(host, enable);
> -       sdhci_runtime_pm_put(host);
>  }
>
>  static void sdhci_card_event(struct mmc_host *mmc)
> @@ -2025,7 +2070,6 @@ static const struct mmc_host_ops sdhci_ops = {
>         .enable_sdio_irq = sdhci_enable_sdio_irq,
>         .start_signal_voltage_switch    = sdhci_start_signal_voltage_switch,
>         .execute_tuning                 = sdhci_execute_tuning,
> -       .enable_preset_value            = sdhci_enable_preset_value,
>         .card_event                     = sdhci_card_event,
>  };
>
> @@ -2598,8 +2642,12 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
>         sdhci_do_set_ios(host, &host->mmc->ios);
>
>         sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
> -       if (host_flags & SDHCI_PV_ENABLED)
> -               sdhci_do_enable_preset_value(host, true);
> +       if ((host_flags & SDHCI_PV_ENABLED) &&
> +               !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
> +               spin_lock_irqsave(&host->lock, flags);
> +               sdhci_enable_preset_value(host, true);
> +               spin_unlock_irqrestore(&host->lock, flags);
> +       }
>
>         /* Set the re-tuning expiration flag */
>         if (host->flags & SDHCI_USING_RETUNING_TIMER)
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index e0c9120..df13303 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -229,6 +229,18 @@
>
>  /* 60-FB reserved */
>
> +#define SDHCI_PRESET_FOR_SDR12 0x66
> +#define SDHCI_PRESET_FOR_SDR25 0x68
> +#define SDHCI_PRESET_FOR_SDR50 0x6A
> +#define SDHCI_PRESET_FOR_SDR104        0x6C
> +#define SDHCI_PRESET_FOR_DDR50 0x6E
> +#define SDHCI_PRESET_DRV_MASK  0xC000
> +#define SDHCI_PRESET_DRV_SHIFT  14
> +#define SDHCI_PRESET_CLKGEN_SEL_MASK   0x400
> +#define SDHCI_PRESET_CLKGEN_SEL_SHIFT  10
> +#define SDHCI_PRESET_SDCLK_FREQ_MASK   0x3FF
> +#define SDHCI_PRESET_SDCLK_FREQ_SHIFT  0
> +
>  #define SDHCI_SLOT_INT_STATUS  0xFC
>
>  #define SDHCI_HOST_VERSION     0xFE
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 61a10c1..52a55b6 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -133,7 +133,6 @@ struct mmc_host_ops {
>
>         /* 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);
>         void    (*card_event)(struct mmc_host *host);
> diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
> index 4bbc330..b838ffc 100644
> --- a/include/linux/mmc/sdhci.h
> +++ b/include/linux/mmc/sdhci.h
> @@ -94,6 +94,7 @@ struct sdhci_host {
>  #define SDHCI_QUIRK2_HOST_NO_CMD23                     (1<<1)
>  /* The system physically doesn't support 1.8v, even if the host does */
>  #define SDHCI_QUIRK2_NO_1_8_V                          (1<<2)
> +#define SDHCI_QUIRK2_PRESET_VALUE_BROKEN               (1<<3)
>
>         int irq;                /* Device IRQ */
>         void __iomem *ioaddr;   /* Mapped address */
> --
> 1.7.0.4
>

So, if the enable_preset_value host ops if not needed it shall be removed, good.

Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2012-12-17 21:05 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-12-17 11:21 [PATCH v10 00/12] mmc: sdhci: fixes and enhancements Kevin Liu
2012-12-17 11:21 ` [PATCH v10 01/12] mmc: sdhci: fix transfer mode setting bug for cmds w/o data transfer Kevin Liu
2012-12-17 11:21 ` [PATCH v10 02/12] mmc: sdhci: refine code for clock disable/enable in set ios Kevin Liu
2012-12-17 11:21 ` [PATCH v10 03/12] mmc: sdhci: add function to get retunig timer count Kevin Liu
2012-12-17 11:22 ` [PATCH v10 04/12] mmc: sdhci: correct voltage support caps setting Kevin Liu
2012-12-17 11:22 ` [PATCH v10 05/12] mmc: sdhci: clean code for SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK selected Kevin Liu
2012-12-17 11:22 ` [PATCH v10 06/12] mmc: sdhci: remove check for CONFIG_REGULATOR Kevin Liu
2012-12-17 11:22 ` [PATCH v10 07/12] mmc: sdhci: fix the bug that DDR50 can't work for emmc in default code Kevin Liu
2012-12-17 11:22 ` [PATCH v10 08/12] mmc: sdhci: remove set_uhs_signaling function Kevin Liu
2012-12-17 11:22 ` [PATCH v10 09/12] mmc: sdhci: enhance preset value function Kevin Liu
2012-12-17 21:05   ` Ulf Hansson
2012-12-17 11:22 ` [PATCH v10 10/12] mmc: sdhci: keep the saved clock var up to date Kevin Liu
2012-12-17 11:22 ` [PATCH v10 11/12] mmc: sdhci: add notifier for regulator vqmmc Kevin Liu
2012-12-17 11:22 ` [PATCH v10 12/12] mmc: sdhci-pxav3: add regulator notifier for vqmmc Kevin Liu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.