All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kishon Vijay Abraham I <kishon@ti.com>
To: Ulf Hansson <ulf.hansson@linaro.org>,
	Tony Lindgren <tony@atomide.com>,
	Adrian Hunter <adrian.hunter@intel.com>
Cc: Rob Herring <robh+dt@kernel.org>,
	Mark Rutland <mark.rutland@arm.com>,
	Russell King <linux@armlinux.org.uk>,
	Kishon Vijay Abraham I <kishon@ti.com>,
	<linux-mmc@vger.kernel.org>, <devicetree@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>, <linux-omap@vger.kernel.org>,
	<linux-arm-kernel@lists.infradead.org>
Subject: [PATCH v2 04/16] mmc: sdhci-omap: Add tuning support
Date: Mon, 5 Feb 2018 18:20:17 +0530	[thread overview]
Message-ID: <20180205125029.21570-5-kishon@ti.com> (raw)
In-Reply-To: <20180205125029.21570-1-kishon@ti.com>

MMC tuning procedure is required to support SD card
UHS1-SDR104 mode and EMMC HS200 mode.

SDR104/HS200 DLL Tuning Procedure for AM572x platform is mentioned
in Figure 25-51. SDR104/HS200 DLL Tuning Procedure of
AM572x Sitara Processors Silicon Revision 2.0, 1.1 TRM
(SPRUHZ6I - October 2014–Revised April 2017 [1]).

The tuning function sdhci_omap_execute_tuning() will only be
called by the MMC/SD core if the corresponding speed modes
are supported by the OMAP silicon which is set in the mmc
host "caps" field.

[1] -> http://www.ti.com/lit/ug/spruhz6i/spruhz6i.pdf

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/host/sdhci-omap.c | 130 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 130 insertions(+)

diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
index 86b6cc0a5380..36e0626d3de2 100644
--- a/drivers/mmc/host/sdhci-omap.c
+++ b/drivers/mmc/host/sdhci-omap.c
@@ -37,6 +37,13 @@
 #define CON_INIT		BIT(1)
 #define CON_OD			BIT(0)
 
+#define SDHCI_OMAP_DLL		0x0134
+#define DLL_SWT			BIT(20)
+#define DLL_FORCE_SR_C_SHIFT	13
+#define DLL_FORCE_SR_C_MASK	(0x7f << DLL_FORCE_SR_C_SHIFT)
+#define DLL_FORCE_VALUE		BIT(12)
+#define DLL_CALIB		BIT(1)
+
 #define SDHCI_OMAP_CMD		0x20c
 
 #define SDHCI_OMAP_PSTATE	0x0224
@@ -63,12 +70,16 @@
 
 #define SDHCI_OMAP_AC12		0x23c
 #define AC12_V1V8_SIGEN		BIT(19)
+#define AC12_SCLK_SEL		BIT(23)
 
 #define SDHCI_OMAP_CAPA		0x240
 #define CAPA_VS33		BIT(24)
 #define CAPA_VS30		BIT(25)
 #define CAPA_VS18		BIT(26)
 
+#define SDHCI_OMAP_CAPA2	0x0244
+#define CAPA2_TSDR50		BIT(13)
+
 #define SDHCI_OMAP_TIMEOUT	1		/* 1 msec */
 
 #define SYSCTL_CLKD_MAX		0x3FF
@@ -77,6 +88,8 @@
 #define IOV_3V0			3000000		/* 300000 uV */
 #define IOV_3V3			3300000		/* 330000 uV */
 
+#define MAX_PHASE_DELAY		0x7C
+
 struct sdhci_omap_data {
 	u32 offset;
 };
@@ -198,6 +211,120 @@ static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host,
 	}
 }
 
+static inline void sdhci_omap_set_dll(struct sdhci_omap_host *omap_host,
+				      int count)
+{
+	int i;
+	u32 reg;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
+	reg |= DLL_FORCE_VALUE;
+	reg &= ~DLL_FORCE_SR_C_MASK;
+	reg |= (count << DLL_FORCE_SR_C_SHIFT);
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+
+	reg |= DLL_CALIB;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+	for (i = 0; i < 1000; i++) {
+		reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
+		if (reg & DLL_CALIB)
+			break;
+	}
+	reg &= ~DLL_CALIB;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+}
+
+static void sdhci_omap_disable_tuning(struct sdhci_omap_host *omap_host)
+{
+	u32 reg;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12);
+	reg &= ~AC12_SCLK_SEL;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_AC12, reg);
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
+	reg &= ~(DLL_FORCE_VALUE | DLL_SWT);
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+}
+
+static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
+	struct device *dev = omap_host->dev;
+	struct mmc_ios *ios = &mmc->ios;
+	u32 start_window = 0, max_window = 0;
+	u8 cur_match, prev_match = 0;
+	u32 length = 0, max_len = 0;
+	u32 phase_delay = 0;
+	int ret = 0;
+	u32 reg;
+
+	pltfm_host = sdhci_priv(host);
+	omap_host = sdhci_pltfm_priv(pltfm_host);
+	dev = omap_host->dev;
+
+	/* clock tuning is not needed for upto 52MHz */
+	if (ios->clock <= 52000000)
+		return 0;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA2);
+	if (ios->timing == MMC_TIMING_UHS_SDR50 && !(reg & CAPA2_TSDR50))
+		return 0;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
+	reg |= DLL_SWT;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+
+	while (phase_delay <= MAX_PHASE_DELAY) {
+		sdhci_omap_set_dll(omap_host, phase_delay);
+
+		cur_match = !mmc_send_tuning(mmc, opcode, NULL);
+		if (cur_match) {
+			if (prev_match) {
+				length++;
+			} else {
+				start_window = phase_delay;
+				length = 1;
+			}
+		}
+
+		if (length > max_len) {
+			max_window = start_window;
+			max_len = length;
+		}
+
+		prev_match = cur_match;
+		phase_delay += 4;
+	}
+
+	if (!max_len) {
+		dev_err(dev, "Unable to find match\n");
+		ret = -EIO;
+		goto tuning_error;
+	}
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12);
+	if (!(reg & AC12_SCLK_SEL)) {
+		ret = -EIO;
+		goto tuning_error;
+	}
+
+	phase_delay = max_window + 4 * (max_len >> 1);
+	sdhci_omap_set_dll(omap_host, phase_delay);
+
+	goto ret;
+
+tuning_error:
+	dev_err(dev, "Tuning failed\n");
+	sdhci_omap_disable_tuning(omap_host);
+
+ret:
+	sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+	return ret;
+}
+
 static int sdhci_omap_card_busy(struct mmc_host *mmc)
 {
 	u32 reg, ac12;
@@ -299,6 +426,8 @@ static int sdhci_omap_start_signal_voltage_switch(struct mmc_host *mmc,
 static void sdhci_omap_set_power_mode(struct sdhci_omap_host *omap_host,
 				      u8 power_mode)
 {
+	if (omap_host->bus_mode == MMC_POWER_OFF)
+		sdhci_omap_disable_tuning(omap_host);
 	omap_host->power_mode = power_mode;
 }
 
@@ -635,6 +764,7 @@ static int sdhci_omap_probe(struct platform_device *pdev)
 					sdhci_omap_start_signal_voltage_switch;
 	host->mmc_host_ops.set_ios = sdhci_omap_set_ios;
 	host->mmc_host_ops.card_busy = sdhci_omap_card_busy;
+	host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning;
 
 	sdhci_read_caps(host);
 	host->caps |= SDHCI_CAN_DO_ADMA2;
-- 
2.11.0

WARNING: multiple messages have this Message-ID (diff)
From: Kishon Vijay Abraham I <kishon@ti.com>
To: Ulf Hansson <ulf.hansson@linaro.org>,
	Tony Lindgren <tony@atomide.com>,
	Adrian Hunter <adrian.hunter@intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-mmc@vger.kernel.org, Russell King <linux@armlinux.org.uk>,
	Kishon Vijay Abraham I <kishon@ti.com>,
	Rob Herring <robh+dt@kernel.org>,
	linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2 04/16] mmc: sdhci-omap: Add tuning support
Date: Mon, 5 Feb 2018 18:20:17 +0530	[thread overview]
Message-ID: <20180205125029.21570-5-kishon@ti.com> (raw)
In-Reply-To: <20180205125029.21570-1-kishon@ti.com>

MMC tuning procedure is required to support SD card
UHS1-SDR104 mode and EMMC HS200 mode.

SDR104/HS200 DLL Tuning Procedure for AM572x platform is mentioned
in Figure 25-51. SDR104/HS200 DLL Tuning Procedure of
AM572x Sitara Processors Silicon Revision 2.0, 1.1 TRM
(SPRUHZ6I - October 2014–Revised April 2017 [1]).

The tuning function sdhci_omap_execute_tuning() will only be
called by the MMC/SD core if the corresponding speed modes
are supported by the OMAP silicon which is set in the mmc
host "caps" field.

[1] -> http://www.ti.com/lit/ug/spruhz6i/spruhz6i.pdf

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/host/sdhci-omap.c | 130 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 130 insertions(+)

diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
index 86b6cc0a5380..36e0626d3de2 100644
--- a/drivers/mmc/host/sdhci-omap.c
+++ b/drivers/mmc/host/sdhci-omap.c
@@ -37,6 +37,13 @@
 #define CON_INIT		BIT(1)
 #define CON_OD			BIT(0)
 
+#define SDHCI_OMAP_DLL		0x0134
+#define DLL_SWT			BIT(20)
+#define DLL_FORCE_SR_C_SHIFT	13
+#define DLL_FORCE_SR_C_MASK	(0x7f << DLL_FORCE_SR_C_SHIFT)
+#define DLL_FORCE_VALUE		BIT(12)
+#define DLL_CALIB		BIT(1)
+
 #define SDHCI_OMAP_CMD		0x20c
 
 #define SDHCI_OMAP_PSTATE	0x0224
@@ -63,12 +70,16 @@
 
 #define SDHCI_OMAP_AC12		0x23c
 #define AC12_V1V8_SIGEN		BIT(19)
+#define AC12_SCLK_SEL		BIT(23)
 
 #define SDHCI_OMAP_CAPA		0x240
 #define CAPA_VS33		BIT(24)
 #define CAPA_VS30		BIT(25)
 #define CAPA_VS18		BIT(26)
 
+#define SDHCI_OMAP_CAPA2	0x0244
+#define CAPA2_TSDR50		BIT(13)
+
 #define SDHCI_OMAP_TIMEOUT	1		/* 1 msec */
 
 #define SYSCTL_CLKD_MAX		0x3FF
@@ -77,6 +88,8 @@
 #define IOV_3V0			3000000		/* 300000 uV */
 #define IOV_3V3			3300000		/* 330000 uV */
 
+#define MAX_PHASE_DELAY		0x7C
+
 struct sdhci_omap_data {
 	u32 offset;
 };
@@ -198,6 +211,120 @@ static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host,
 	}
 }
 
+static inline void sdhci_omap_set_dll(struct sdhci_omap_host *omap_host,
+				      int count)
+{
+	int i;
+	u32 reg;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
+	reg |= DLL_FORCE_VALUE;
+	reg &= ~DLL_FORCE_SR_C_MASK;
+	reg |= (count << DLL_FORCE_SR_C_SHIFT);
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+
+	reg |= DLL_CALIB;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+	for (i = 0; i < 1000; i++) {
+		reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
+		if (reg & DLL_CALIB)
+			break;
+	}
+	reg &= ~DLL_CALIB;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+}
+
+static void sdhci_omap_disable_tuning(struct sdhci_omap_host *omap_host)
+{
+	u32 reg;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12);
+	reg &= ~AC12_SCLK_SEL;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_AC12, reg);
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
+	reg &= ~(DLL_FORCE_VALUE | DLL_SWT);
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+}
+
+static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
+	struct device *dev = omap_host->dev;
+	struct mmc_ios *ios = &mmc->ios;
+	u32 start_window = 0, max_window = 0;
+	u8 cur_match, prev_match = 0;
+	u32 length = 0, max_len = 0;
+	u32 phase_delay = 0;
+	int ret = 0;
+	u32 reg;
+
+	pltfm_host = sdhci_priv(host);
+	omap_host = sdhci_pltfm_priv(pltfm_host);
+	dev = omap_host->dev;
+
+	/* clock tuning is not needed for upto 52MHz */
+	if (ios->clock <= 52000000)
+		return 0;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA2);
+	if (ios->timing == MMC_TIMING_UHS_SDR50 && !(reg & CAPA2_TSDR50))
+		return 0;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
+	reg |= DLL_SWT;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+
+	while (phase_delay <= MAX_PHASE_DELAY) {
+		sdhci_omap_set_dll(omap_host, phase_delay);
+
+		cur_match = !mmc_send_tuning(mmc, opcode, NULL);
+		if (cur_match) {
+			if (prev_match) {
+				length++;
+			} else {
+				start_window = phase_delay;
+				length = 1;
+			}
+		}
+
+		if (length > max_len) {
+			max_window = start_window;
+			max_len = length;
+		}
+
+		prev_match = cur_match;
+		phase_delay += 4;
+	}
+
+	if (!max_len) {
+		dev_err(dev, "Unable to find match\n");
+		ret = -EIO;
+		goto tuning_error;
+	}
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12);
+	if (!(reg & AC12_SCLK_SEL)) {
+		ret = -EIO;
+		goto tuning_error;
+	}
+
+	phase_delay = max_window + 4 * (max_len >> 1);
+	sdhci_omap_set_dll(omap_host, phase_delay);
+
+	goto ret;
+
+tuning_error:
+	dev_err(dev, "Tuning failed\n");
+	sdhci_omap_disable_tuning(omap_host);
+
+ret:
+	sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+	return ret;
+}
+
 static int sdhci_omap_card_busy(struct mmc_host *mmc)
 {
 	u32 reg, ac12;
@@ -299,6 +426,8 @@ static int sdhci_omap_start_signal_voltage_switch(struct mmc_host *mmc,
 static void sdhci_omap_set_power_mode(struct sdhci_omap_host *omap_host,
 				      u8 power_mode)
 {
+	if (omap_host->bus_mode == MMC_POWER_OFF)
+		sdhci_omap_disable_tuning(omap_host);
 	omap_host->power_mode = power_mode;
 }
 
@@ -635,6 +764,7 @@ static int sdhci_omap_probe(struct platform_device *pdev)
 					sdhci_omap_start_signal_voltage_switch;
 	host->mmc_host_ops.set_ios = sdhci_omap_set_ios;
 	host->mmc_host_ops.card_busy = sdhci_omap_card_busy;
+	host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning;
 
 	sdhci_read_caps(host);
 	host->caps |= SDHCI_CAN_DO_ADMA2;
-- 
2.11.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

WARNING: multiple messages have this Message-ID (diff)
From: kishon@ti.com (Kishon Vijay Abraham I)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2 04/16] mmc: sdhci-omap: Add tuning support
Date: Mon, 5 Feb 2018 18:20:17 +0530	[thread overview]
Message-ID: <20180205125029.21570-5-kishon@ti.com> (raw)
In-Reply-To: <20180205125029.21570-1-kishon@ti.com>

MMC tuning procedure is required to support SD card
UHS1-SDR104 mode and EMMC HS200 mode.

SDR104/HS200 DLL Tuning Procedure for AM572x platform is mentioned
in Figure 25-51. SDR104/HS200 DLL Tuning Procedure of
AM572x Sitara Processors Silicon Revision 2.0, 1.1 TRM
(SPRUHZ6I - October 2014?Revised April 2017 [1]).

The tuning function sdhci_omap_execute_tuning() will only be
called by the MMC/SD core if the corresponding speed modes
are supported by the OMAP silicon which is set in the mmc
host "caps" field.

[1] -> http://www.ti.com/lit/ug/spruhz6i/spruhz6i.pdf

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/host/sdhci-omap.c | 130 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 130 insertions(+)

diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
index 86b6cc0a5380..36e0626d3de2 100644
--- a/drivers/mmc/host/sdhci-omap.c
+++ b/drivers/mmc/host/sdhci-omap.c
@@ -37,6 +37,13 @@
 #define CON_INIT		BIT(1)
 #define CON_OD			BIT(0)
 
+#define SDHCI_OMAP_DLL		0x0134
+#define DLL_SWT			BIT(20)
+#define DLL_FORCE_SR_C_SHIFT	13
+#define DLL_FORCE_SR_C_MASK	(0x7f << DLL_FORCE_SR_C_SHIFT)
+#define DLL_FORCE_VALUE		BIT(12)
+#define DLL_CALIB		BIT(1)
+
 #define SDHCI_OMAP_CMD		0x20c
 
 #define SDHCI_OMAP_PSTATE	0x0224
@@ -63,12 +70,16 @@
 
 #define SDHCI_OMAP_AC12		0x23c
 #define AC12_V1V8_SIGEN		BIT(19)
+#define AC12_SCLK_SEL		BIT(23)
 
 #define SDHCI_OMAP_CAPA		0x240
 #define CAPA_VS33		BIT(24)
 #define CAPA_VS30		BIT(25)
 #define CAPA_VS18		BIT(26)
 
+#define SDHCI_OMAP_CAPA2	0x0244
+#define CAPA2_TSDR50		BIT(13)
+
 #define SDHCI_OMAP_TIMEOUT	1		/* 1 msec */
 
 #define SYSCTL_CLKD_MAX		0x3FF
@@ -77,6 +88,8 @@
 #define IOV_3V0			3000000		/* 300000 uV */
 #define IOV_3V3			3300000		/* 330000 uV */
 
+#define MAX_PHASE_DELAY		0x7C
+
 struct sdhci_omap_data {
 	u32 offset;
 };
@@ -198,6 +211,120 @@ static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host,
 	}
 }
 
+static inline void sdhci_omap_set_dll(struct sdhci_omap_host *omap_host,
+				      int count)
+{
+	int i;
+	u32 reg;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
+	reg |= DLL_FORCE_VALUE;
+	reg &= ~DLL_FORCE_SR_C_MASK;
+	reg |= (count << DLL_FORCE_SR_C_SHIFT);
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+
+	reg |= DLL_CALIB;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+	for (i = 0; i < 1000; i++) {
+		reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
+		if (reg & DLL_CALIB)
+			break;
+	}
+	reg &= ~DLL_CALIB;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+}
+
+static void sdhci_omap_disable_tuning(struct sdhci_omap_host *omap_host)
+{
+	u32 reg;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12);
+	reg &= ~AC12_SCLK_SEL;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_AC12, reg);
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
+	reg &= ~(DLL_FORCE_VALUE | DLL_SWT);
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+}
+
+static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
+	struct device *dev = omap_host->dev;
+	struct mmc_ios *ios = &mmc->ios;
+	u32 start_window = 0, max_window = 0;
+	u8 cur_match, prev_match = 0;
+	u32 length = 0, max_len = 0;
+	u32 phase_delay = 0;
+	int ret = 0;
+	u32 reg;
+
+	pltfm_host = sdhci_priv(host);
+	omap_host = sdhci_pltfm_priv(pltfm_host);
+	dev = omap_host->dev;
+
+	/* clock tuning is not needed for upto 52MHz */
+	if (ios->clock <= 52000000)
+		return 0;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA2);
+	if (ios->timing == MMC_TIMING_UHS_SDR50 && !(reg & CAPA2_TSDR50))
+		return 0;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
+	reg |= DLL_SWT;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+
+	while (phase_delay <= MAX_PHASE_DELAY) {
+		sdhci_omap_set_dll(omap_host, phase_delay);
+
+		cur_match = !mmc_send_tuning(mmc, opcode, NULL);
+		if (cur_match) {
+			if (prev_match) {
+				length++;
+			} else {
+				start_window = phase_delay;
+				length = 1;
+			}
+		}
+
+		if (length > max_len) {
+			max_window = start_window;
+			max_len = length;
+		}
+
+		prev_match = cur_match;
+		phase_delay += 4;
+	}
+
+	if (!max_len) {
+		dev_err(dev, "Unable to find match\n");
+		ret = -EIO;
+		goto tuning_error;
+	}
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12);
+	if (!(reg & AC12_SCLK_SEL)) {
+		ret = -EIO;
+		goto tuning_error;
+	}
+
+	phase_delay = max_window + 4 * (max_len >> 1);
+	sdhci_omap_set_dll(omap_host, phase_delay);
+
+	goto ret;
+
+tuning_error:
+	dev_err(dev, "Tuning failed\n");
+	sdhci_omap_disable_tuning(omap_host);
+
+ret:
+	sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+	return ret;
+}
+
 static int sdhci_omap_card_busy(struct mmc_host *mmc)
 {
 	u32 reg, ac12;
@@ -299,6 +426,8 @@ static int sdhci_omap_start_signal_voltage_switch(struct mmc_host *mmc,
 static void sdhci_omap_set_power_mode(struct sdhci_omap_host *omap_host,
 				      u8 power_mode)
 {
+	if (omap_host->bus_mode == MMC_POWER_OFF)
+		sdhci_omap_disable_tuning(omap_host);
 	omap_host->power_mode = power_mode;
 }
 
@@ -635,6 +764,7 @@ static int sdhci_omap_probe(struct platform_device *pdev)
 					sdhci_omap_start_signal_voltage_switch;
 	host->mmc_host_ops.set_ios = sdhci_omap_set_ios;
 	host->mmc_host_ops.card_busy = sdhci_omap_card_busy;
+	host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning;
 
 	sdhci_read_caps(host);
 	host->caps |= SDHCI_CAN_DO_ADMA2;
-- 
2.11.0

  parent reply	other threads:[~2018-02-05 12:55 UTC|newest]

Thread overview: 93+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-02-05 12:50 [PATCH v2 00/16] mmc: sdhci-omap: Add UHS/HS200 mode support Kishon Vijay Abraham I
2018-02-05 12:50 ` Kishon Vijay Abraham I
2018-02-05 12:50 ` Kishon Vijay Abraham I
2018-02-05 12:50 ` [PATCH v2 01/16] mmc: sdhci-omap: Update 'power_mode' outside sdhci_omap_init_74_clocks Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50 ` [PATCH v2 02/16] mmc: sdhci-omap: Add card_busy host ops Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50 ` [PATCH v2 03/16] mmc: sdhci-omap: Add custom set_uhs_signaling sdhci_host ops Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50 ` Kishon Vijay Abraham I [this message]
2018-02-05 12:50   ` [PATCH v2 04/16] mmc: sdhci-omap: Add tuning support Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50 ` [PATCH v2 05/16] mmc: sdhci-omap: Workaround for Errata i802 Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50 ` [PATCH v2 06/16] mmc: sdhci_omap: Add support to set IODELAY values Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50 ` [PATCH v2 07/16] mmc: sdhci_omap: Fix sdhci-omap quirks Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50 ` [PATCH v2 08/16] mmc: sdhci-omap: Add support to override f_max and iodelay from pdata Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-14  9:53   ` Ulf Hansson
2018-02-14  9:53     ` Ulf Hansson
2018-02-14 17:24     ` Tony Lindgren
2018-02-14 17:24       ` Tony Lindgren
2018-02-16  8:08       ` Kishon Vijay Abraham I
2018-02-16  8:08         ` Kishon Vijay Abraham I
2018-02-16  8:08         ` Kishon Vijay Abraham I
2018-02-05 12:50 ` [PATCH v2 09/16] mmc: sdhci: Add quirk to disable HW timeout Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-19  8:51   ` Adrian Hunter
2018-02-19  8:51     ` Adrian Hunter
2018-02-19  8:51     ` Adrian Hunter
2018-03-05  9:30     ` Kishon Vijay Abraham I
2018-03-05  9:30       ` Kishon Vijay Abraham I
2018-03-05  9:30       ` Kishon Vijay Abraham I
2018-03-05  9:38       ` Adrian Hunter
2018-03-05  9:38         ` Adrian Hunter
2018-03-14 13:25         ` Kishon Vijay Abraham I
2018-03-14 13:25           ` Kishon Vijay Abraham I
2018-03-14 13:25           ` Kishon Vijay Abraham I
2018-02-05 12:50 ` [PATCH v2 10/16] mmc: sdhci: Fix to use data_timer only for data line commands Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-19  8:03   ` Adrian Hunter
2018-02-19  8:03     ` Adrian Hunter
2018-02-19  8:03     ` Adrian Hunter
2018-02-19 12:55     ` Kishon Vijay Abraham I
2018-02-19 12:55       ` Kishon Vijay Abraham I
2018-02-19 12:55       ` Kishon Vijay Abraham I
2018-02-05 12:50 ` [PATCH v2 11/16] mmc: sdhci: Program a relatively accurate SW timeout value Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-16  7:17   ` Kishon Vijay Abraham I
2018-02-16  7:17     ` Kishon Vijay Abraham I
2018-02-16  7:17     ` Kishon Vijay Abraham I
2018-02-19  9:24   ` Adrian Hunter
2018-02-19  9:24     ` Adrian Hunter
2018-02-19  9:24     ` Adrian Hunter
2018-02-19 13:13     ` Adrian Hunter
2018-02-19 13:13       ` Adrian Hunter
2018-02-19 13:13       ` Adrian Hunter
2018-02-05 12:50 ` [PATCH v2 12/16] mmc: sdhci-omap: Workaround for Errata i834 Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50 ` [PATCH v2 13/16] dt-bindings: sdhci-omap: Add K2G specific binding Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50 ` [PATCH v2 14/16] mmc: sdhci-omap: Add support for MMC/SD controller in k2g SoC Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50 ` [PATCH v2 15/16] mmc: sdhci-omap: Add SPDX identifier Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 21:50   ` Joe Perches
2018-02-05 21:50     ` Joe Perches
2018-02-05 21:50     ` Joe Perches
2018-02-19  9:33   ` Adrian Hunter
2018-02-19  9:33     ` Adrian Hunter
2018-02-19  9:33     ` Adrian Hunter
2018-02-05 12:50 ` [PATCH v2 16/16] ARM: OMAP2+: Use sdhci-omap specific pdata-quirks for MMC/SD on DRA74x EVM Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-05 12:50   ` Kishon Vijay Abraham I
2018-02-14 10:38 ` [PATCH v2 00/16] mmc: sdhci-omap: Add UHS/HS200 mode support Ulf Hansson
2018-02-14 10:38   ` Ulf Hansson
2018-02-14 10:38   ` Ulf Hansson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180205125029.21570-5-kishon@ti.com \
    --to=kishon@ti.com \
    --cc=adrian.hunter@intel.com \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mmc@vger.kernel.org \
    --cc=linux-omap@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=mark.rutland@arm.com \
    --cc=robh+dt@kernel.org \
    --cc=tony@atomide.com \
    --cc=ulf.hansson@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.