Skip to contentSkip to conversation

Add clk-rates and DDR support to sdhci-msm

PATCH Superseded Ritesh Harjani 2 participants 11 messages Aug 16, 2016 – Aug 17, 2016

Subsystems (5)

v2 of 9 Superseded Latest is v9 →

lore
Share & tools
lore
#0 lore raw

v2 cover Add clk-rates and DDR support to sdhci-msm

Hi All,

This is v2 version of the patch series. Have addressed few comments from Jaehoon & Shawn. These were mainly related to not use any extra quirks or not to add any unnecessary callback into sdhci.

Changes from v1->v2 :-
1. Removed patch 06 & 08 from v1 patch series[1]. Instead have implemented __sdhci_msm_set_clock version of sdhci_set_clock in sdhci_msm driver itself in patch 07 of this patch series.
2. Enabled extra quirk (SDHCI_QUIRK2_PRESET_VALUE_BROKEN) in patch 05 of this patch series.

Description of patches :-
This patchset adds clk-rates & other required changes to upstream sdhci-msm driver from codeaurora tree.
It has been tested on a db410c Dragonboard and msm8996 based platform.

Patch 0001 - Adds updated dll sequence for newer controllers which has minor_version >= 0x42. This is required for msm8996.

MSM controller HW recommendation is to use the base MCI clock and directly control this MCI clock at GCC in order to change the clk-rate.
Patches 02-06 bring in required change for this to sdhci-msm and DT of db410c.

MSM controller would require 2x clock rate from source for DDR bus speed modes. Patch 07 adds this support.

Patch 08 - adds DDR support in DT for sdhc1 of msm8916.

[1]:- http://www.spinics.net/lists/linux-mmc/msg38467.html

Ritesh Harjani (7):
mmc: sdhci-msm: add pltfm_data support to get clk-rates from DT
arm64: dts: qcom: msm8916: Add clk-rates to sdhc1 & sdhc2
mmc: sdhci-msm: Add get_min_clock() and get_max_clock() callback
mmc: sdhci-msm: Enable few quirks
mmc: sdhci-msm: Implement set_clock callback for sdhci-msm
mmc: sdhci-msm: Add clock changes for DDR mode.
arm64: dts: qcom: msm8916: Add ddr support to sdhc1

Venkat Gopalakrishnan (1):
mmc: sdhci-msm: Update DLL reset sequence

 .../devicetree/bindings/mmc/sdhci-msm.txt          |   1 +
 arch/arm64/boot/dts/qcom/msm8916.dtsi              |   5 +
 drivers/mmc/host/sdhci-msm.c                       | 256 ++++++++++++++++++++-
 3 files changed, 260 insertions(+), 2 deletions(-)
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, 
a Linux Foundation Collaborative Project.
#1 lore raw

PATCH v2 1/8 mmc: sdhci-msm: Update DLL reset sequence

From: Venkat Gopalakrishnan <[email protected]>

SDCC core with minor version >= 0x42 requires a change in the reset sequence for DLL tuning. Make necessary changes as needed.

Without this patch we see below errors on such SDHC controllers
sdhci_msm 7464900.sdhci: mmc0: DLL failed to LOCK
mmc0: tuning execution failed: -110

---
 drivers/mmc/host/sdhci-msm.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)
drivers/mmc/host/sdhci-msm.c +45 -0
index 8ef44a2a..9e08424 100644
@@ -58,11 +58,17 @@
 #define CORE_DLL_CONFIG		0x100
 #define CORE_DLL_STATUS		0x108
 
+#define CORE_DLL_CONFIG_2	0x1b4
+#define CORE_FLL_CYCLE_CNT	BIT(18)
+#define CORE_DLL_CLOCK_DISABLE	BIT(21)
+
 #define CORE_VENDOR_SPEC	0x10c
 #define CORE_CLK_PWRSAVE	BIT(1)
 
 #define CORE_VENDOR_SPEC_CAPABILITIES0	0x11c
 
+#define TCXO_FREQ		19200000
+
 #define CDR_SELEXT_SHIFT	20
 #define CDR_SELEXT_MASK		(0xf << CDR_SELEXT_SHIFT)
 #define CMUX_SHIFT_PHASE_SHIFT	24
@@ -76,6 +82,7 @@ struct sdhci_msm_host {
 	struct clk *pclk;	/* SDHC peripheral bus clock */
 	struct clk *bus_clk;	/* SDHC bus voter clock */
 	struct mmc_host *mmc;
+	bool use_updated_dll_reset;
 };
 
 /* Platform specific tuning */
@@ -303,6 +310,8 @@ static inline void msm_cm_dll_set_freq(struct sdhci_host *host)
 static int msm_init_cm_dll(struct sdhci_host *host)
 {
 	struct mmc_host *mmc = host->mmc;
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
 	int wait_cnt = 50;
 	unsigned long flags;
 
@@ -316,6 +325,15 @@ static int msm_init_cm_dll(struct sdhci_host *host)
 	writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
 			& ~CORE_CLK_PWRSAVE), host->ioaddr + CORE_VENDOR_SPEC);
 
+	if (msm_host->use_updated_dll_reset) {
+		writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+				& ~CORE_CK_OUT_EN),
+				host->ioaddr + CORE_DLL_CONFIG);
+		writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
+				| CORE_DLL_CLOCK_DISABLE),
+				host->ioaddr + CORE_DLL_CONFIG_2);
+	}
+
 	/* Write 1 to DLL_RST bit of DLL_CONFIG register */
 	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
 			| CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
@@ -325,6 +343,22 @@ static int msm_init_cm_dll(struct sdhci_host *host)
 			| CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
 	msm_cm_dll_set_freq(host);
 
+	if (msm_host->use_updated_dll_reset) {
+		u32 mclk_freq = 0;
+
+		if ((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
+					& CORE_FLL_CYCLE_CNT))
+			mclk_freq = (u32) ((host->clock / TCXO_FREQ) * 8);
+		else
+			mclk_freq = (u32) ((host->clock / TCXO_FREQ) * 4);
+
+		writel_relaxed(((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
+				& ~(0xFF << 10)) | (mclk_freq << 10)),
+				host->ioaddr + CORE_DLL_CONFIG_2);
+		/* wait for 5us before enabling DLL clock */
+		udelay(5);
+	}
+
 	/* Write 0 to DLL_RST bit of DLL_CONFIG register */
 	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
 			& ~CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
@@ -333,6 +367,14 @@ static int msm_init_cm_dll(struct sdhci_host *host)
 	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
 			& ~CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
 
+	if (msm_host->use_updated_dll_reset) {
+		msm_cm_dll_set_freq(host);
+		/* Enable the DLL clock */
+		writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
+				& ~CORE_DLL_CLOCK_DISABLE),
+				host->ioaddr + CORE_DLL_CONFIG_2);
+	}
+
 	/* Set DLL_EN bit to 1. */
 	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
 			| CORE_DLL_EN), host->ioaddr + CORE_DLL_CONFIG);
@@ -631,6 +673,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)
 	dev_dbg(&pdev->dev, "MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n",
 		core_version, core_major, core_minor);
 
+	if ((core_major == 1) && (core_minor >= 0x42))
+		msm_host->use_updated_dll_reset = true;
+
 	/*
 	 * Support for some capabilities is not advertised by newer
 	 * controller versions and must be explicitly enabled.
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, 
a Linux Foundation Collaborative Project.
#2 lore raw

Re: [PATCH v2 1/8] mmc: sdhci-msm: Update DLL reset sequence

On Tue, Aug 16, 2016 at 4:41 AM, Ritesh Harjani <[email protected]> wrote:
[..]

Quoted 1 line
drivers/mmc/host/sdhci-msm.c +0 -0

[..]

drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 334

Quoted 11 lines
drivers/mmc/host/sdhci-msm.c +7 -0
@@ -316,6 +325,15 @@ static int msm_init_cm_dll(struct sdhci_host *host)
        writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
                        & ~CORE_CLK_PWRSAVE), host->ioaddr + CORE_VENDOR_SPEC);
 
+       if (msm_host->use_updated_dll_reset) {
+               writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+                               & ~CORE_CK_OUT_EN),
+                               host->ioaddr + CORE_DLL_CONFIG);
+               writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
+                               | CORE_DLL_CLOCK_DISABLE),
+                               host->ioaddr + CORE_DLL_CONFIG_2);

I know that this follows the pattern of this function, but it's terrible to read. Please unroll each one of these to:

val = readl();
val &= ~mask;
val |= new-bits;
writel(val);

To not mix the style I would suggest that you inject a patch in your series before this one that unrolls the exiting code and then add this.

Quoted 11 lines
drivers/mmc/host/sdhci-msm.c +4 -0
+       }
+
        /* Write 1 to DLL_RST bit of DLL_CONFIG register */
        writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
                        | CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
@@ -325,6 +343,22 @@ static int msm_init_cm_dll(struct sdhci_host *host)
                        | CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
        msm_cm_dll_set_freq(host);
 
+       if (msm_host->use_updated_dll_reset) {
+               u32 mclk_freq = 0;

drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 357

Quoted 10 lines
drivers/mmc/host/sdhci-msm.c +10 -0
+
+               if ((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
+                                       & CORE_FLL_CYCLE_CNT))
+                       mclk_freq = (u32) ((host->clock / TCXO_FREQ) * 8);
+               else
+                       mclk_freq = (u32) ((host->clock / TCXO_FREQ) * 4);
+
+               writel_relaxed(((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
+                               & ~(0xFF << 10)) | (mclk_freq << 10)),
+                               host->ioaddr + CORE_DLL_CONFIG_2);

Dito

Quoted 8 lines
drivers/mmc/host/sdhci-msm.c +4 -0
+               /* wait for 5us before enabling DLL clock */
+               udelay(5);
+       }
+
        /* Write 0 to DLL_RST bit of DLL_CONFIG register */
        writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
                        & ~CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);

drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 375

Quoted 9 lines
drivers/mmc/host/sdhci-msm.c +6 -0
@@ -333,6 +367,14 @@ static int msm_init_cm_dll(struct sdhci_host *host)
        writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
                        & ~CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
 
+       if (msm_host->use_updated_dll_reset) {
+               msm_cm_dll_set_freq(host);
+               /* Enable the DLL clock */
+               writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
+                               & ~CORE_DLL_CLOCK_DISABLE),
+                               host->ioaddr + CORE_DLL_CONFIG_2);

Dito

drivers/mmc/host/sdhci-msm.c static int sdhci_msm_probe(struct platform_device *pdev) · line 678

Quoted 12 lines
drivers/mmc/host/sdhci-msm.c +5 -0
+       }
+
        /* Set DLL_EN bit to 1. */
        writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
                        | CORE_DLL_EN), host->ioaddr + CORE_DLL_CONFIG);
@@ -631,6 +673,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)
        dev_dbg(&pdev->dev, "MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n",
                core_version, core_major, core_minor);
 
+       if ((core_major == 1) && (core_minor >= 0x42))
+               msm_host->use_updated_dll_reset = true;
+

Is it possible to come up with a better name than the "updated DLL sequence", just in case there are future updates to this sequence.

Regards,
Bjorn

#3 lore raw

Re: [PATCH v2 1/8] mmc: sdhci-msm: Update DLL reset sequence

Hi Bjorn,

Thanks for the review -

Quoted 19 lines · Bjorn Andersson

On Tue, Aug 16, 2016 at 4:41 AM, Ritesh Harjani <[email protected]> wrote:
[..]

Quoted 1 line
drivers/mmc/host/sdhci-msm.c +0 -0

[..]

drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 334

Quoted 11 lines
drivers/mmc/host/sdhci-msm.c +7 -0
@@ -316,6 +325,15 @@ static int msm_init_cm_dll(struct sdhci_host *host)
        writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
                        & ~CORE_CLK_PWRSAVE), host->ioaddr + CORE_VENDOR_SPEC);
 
+       if (msm_host->use_updated_dll_reset) {
+               writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+                               & ~CORE_CK_OUT_EN),
+                               host->ioaddr + CORE_DLL_CONFIG);
+               writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
+                               | CORE_DLL_CLOCK_DISABLE),
+                               host->ioaddr + CORE_DLL_CONFIG_2);

I know that this follows the pattern of this function, but it's terrible to read. Please unroll each one of these to:

Quoted 4 lines

val = readl();
val &= ~mask;
val |= new-bits;
writel(val);

Sure.

Quoted 4 lines

To not mix the style I would suggest that you inject a patch in your series before this one that unrolls the exiting code and then add this.

Ok. I think mostly it is only this function which is suffering from the poor style issue which you mentioned. Will make the relevant changes in the next spin.

Quoted 10 lines
Quoted 10 lines
drivers/mmc/host/sdhci-msm.c +2 -0
+       }
+
        /* Write 1 to DLL_RST bit of DLL_CONFIG register */
        writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
                        | CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
@@ -325,6 +343,22 @@ static int msm_init_cm_dll(struct sdhci_host *host)
                        | CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
        msm_cm_dll_set_freq(host);
 
Quoted 14 lines

drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 357

Quoted 12 lines
drivers/mmc/host/sdhci-msm.c +12 -0
+       if (msm_host->use_updated_dll_reset) {
+               u32 mclk_freq = 0;
+
+               if ((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
+                                       & CORE_FLL_CYCLE_CNT))
+                       mclk_freq = (u32) ((host->clock / TCXO_FREQ) * 8);
+               else
+                       mclk_freq = (u32) ((host->clock / TCXO_FREQ) * 4);
+
+               writel_relaxed(((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
+                               & ~(0xFF << 10)) | (mclk_freq << 10)),
+                               host->ioaddr + CORE_DLL_CONFIG_2);

Dito

Ok.

Quoted 12 lines
Quoted 12 lines
drivers/mmc/host/sdhci-msm.c +4 -0
+               /* wait for 5us before enabling DLL clock */
+               udelay(5);
+       }
+
        /* Write 0 to DLL_RST bit of DLL_CONFIG register */
        writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
                        & ~CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
@@ -333,6 +367,14 @@ static int msm_init_cm_dll(struct sdhci_host *host)
        writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
                        & ~CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
 
Quoted 8 lines

drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 375

Quoted 6 lines
drivers/mmc/host/sdhci-msm.c +6 -0
+       if (msm_host->use_updated_dll_reset) {
+               msm_cm_dll_set_freq(host);
+               /* Enable the DLL clock */
+               writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
+                               & ~CORE_DLL_CLOCK_DISABLE),
+                               host->ioaddr + CORE_DLL_CONFIG_2);

Dito

Ok.

Quoted 10 lines
Quoted 10 lines
drivers/mmc/host/sdhci-msm.c +2 -0
+       }
+
        /* Set DLL_EN bit to 1. */
        writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
                        | CORE_DLL_EN), host->ioaddr + CORE_DLL_CONFIG);
@@ -631,6 +673,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)
        dev_dbg(&pdev->dev, "MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n",
                core_version, core_major, core_minor);
 
Quoted 6 lines

drivers/mmc/host/sdhci-msm.c static int sdhci_msm_probe(struct platform_device *pdev) · line 678

Quoted 3 lines
drivers/mmc/host/sdhci-msm.c +3 -0
+       if ((core_major == 1) && (core_minor >= 0x42))
+               msm_host->use_updated_dll_reset = true;
+

Is it possible to come up with a better name than the "updated DLL sequence", just in case there are future updates to this sequence.

Sure, will try and change the flag name too.

Quoted 4 lines

Regards,
Bjorn

#4 lore raw

PATCH v2 2/8 mmc: sdhci-msm: add pltfm_data support to get clk-rates from DT

In reply to Ritesh Harjani

This adds support for sdhc-msm controllers to get supported clk-rates from DT. sdhci-msm would need it's own set_clock ops to be implemented. For this, supported clk-rates needs to be populated in sdhci_msm_pltfm_data.

---
 .../devicetree/bindings/mmc/sdhci-msm.txt          |  1 +
 drivers/mmc/host/sdhci-msm.c                       | 71 ++++++++++++++++++++++
 2 files changed, 72 insertions(+)
Documentation/devicetree/bindings/mmc/sdhci-msm.txt +1 -0
index 485483a..6a83b38 100644
@@ -17,6 +17,7 @@ Required properties:
 	"iface" - Main peripheral bus clock (PCLK/HCLK - AHB Bus clock) (required)
 	"core"	- SDC MMC clock (MCLK) (required)
 	"bus"	- SDCC bus voter clock (optional)
+- clk-rates: Array of supported GCC clock frequencies for sdhc, Units - Hz.
 
 Example:
 
drivers/mmc/host/sdhci-msm.c +71 -0

95 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, 
a Linux Foundation Collaborative Project.
#5 lore raw

PATCH v2 3/8 arm64: dts: qcom: msm8916: Add clk-rates to sdhc1 & sdhc2

In reply to Ritesh Harjani

Add supported msm8916 supported clk-rates for sdhc1 & sdhc2 in DT.

---
 arch/arm64/boot/dts/qcom/msm8916.dtsi | 4 ++++
 1 file changed, 4 insertions(+)
arch/arm64/boot/dts/qcom/msm8916.dtsi +4 -0
index 9681200..5161740 100644
@@ -388,6 +388,8 @@
 			clocks = <&gcc GCC_SDCC1_APPS_CLK>,
 				 <&gcc GCC_SDCC1_AHB_CLK>;
 			clock-names = "core", "iface";
+			clk-rates = <400000 25000000 50000000 100000000
+					177770000>;
 			bus-width = <8>;
 			non-removable;
 			status = "disabled";
@@ -403,6 +405,8 @@
 			clocks = <&gcc GCC_SDCC2_APPS_CLK>,
 				 <&gcc GCC_SDCC2_AHB_CLK>;
 			clock-names = "core", "iface";
+			clk-rates = <400000 25000000 50000000 100000000
+					200000000>;
 			bus-width = <4>;
 			status = "disabled";
 		};
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, 
a Linux Foundation Collaborative Project.
#6 lore raw

PATCH v2 4/8 mmc: sdhci-msm: Add get_min_clock() and get_max_clock() callback

In reply to Ritesh Harjani

This add get_min_clock() and get_max_clock() callback for sdhci-msm. sdhci-msm min/max clocks may be different hence implement these callbacks.

---
 drivers/mmc/host/sdhci-msm.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
drivers/mmc/host/sdhci-msm.c +19 -0
index 2c745c2..5913ce1 100644
@@ -553,6 +553,23 @@ static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static unsigned int sdhci_msm_get_max_clock(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+	int count = msm_host->pdata->clk_table_sz;
+
+	return msm_host->pdata->clk_table[count - 1];
+}
+
+static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+	return msm_host->pdata->clk_table[0];
+}
+
 static const struct of_device_id sdhci_msm_dt_match[] = {
 	{ .compatible = "qcom,sdhci-msm-v4" },
 	{},
@@ -564,6 +581,8 @@ static const struct sdhci_ops sdhci_msm_ops = {
 	.platform_execute_tuning = sdhci_msm_execute_tuning,
 	.reset = sdhci_reset,
 	.set_clock = sdhci_set_clock,
+	.get_min_clock = sdhci_msm_get_min_clock,
+	.get_max_clock = sdhci_msm_get_max_clock,
 	.set_bus_width = sdhci_set_bus_width,
 	.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
 	.voltage_switch = sdhci_msm_voltage_switch,
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, 
a Linux Foundation Collaborative Project.
#7 lore raw

PATCH v2 5/8 mmc: sdhci-msm: Enable few quirks

In reply to Ritesh Harjani

sdhc-msm controller needs this SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN & SDHCI_QUIRK2_PRESET_VALUE_BROKEN to be set. Hence setting it.

---
 drivers/mmc/host/sdhci-msm.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci-msm.c +3 -1
index 5913ce1..9afedac 100644
@@ -591,7 +591,9 @@ static const struct sdhci_ops sdhci_msm_ops = {
 static const struct sdhci_pltfm_data sdhci_msm_pdata = {
 	.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
 		  SDHCI_QUIRK_NO_CARD_NO_RESET |
-		  SDHCI_QUIRK_SINGLE_POWER_WRITE,
+		  SDHCI_QUIRK_SINGLE_POWER_WRITE |
+		  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
 	.ops = &sdhci_msm_ops,
 };
 
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, 
a Linux Foundation Collaborative Project.
#8 lore raw

PATCH v2 6/8 mmc: sdhci-msm: Implement set_clock callback for sdhci-msm

In reply to Ritesh Harjani

sdhci-msm controller may have different clk-rates for each bus speed mode. Thus implement set_clock callback for sdhci-msm driver.

---
 drivers/mmc/host/sdhci-msm.c | 103 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 102 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci-msm.c +102 -1
index 9afedac..1eb5074 100644
@@ -89,6 +89,7 @@ struct sdhci_msm_host {
 	struct mmc_host *mmc;
 	bool use_updated_dll_reset;
 	struct sdhci_msm_pltfm_data *pdata;
+	u32 clk_rate;
 };
 
 /* Platform specific tuning */
@@ -570,6 +571,106 @@ static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host)
 	return msm_host->pdata->clk_table[0];
 }
 
+static unsigned int sdhci_msm_get_msm_clk_rate(struct sdhci_host *host,
+					u32 req_clk)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+	int count = msm_host->pdata->clk_table_sz;
+	unsigned int sel_clk = -1;
+	int cnt;
+
+	if (req_clk < sdhci_msm_get_min_clock(host)) {
+		sel_clk = sdhci_msm_get_min_clock(host);
+		return sel_clk;
+	}
+
+	for (cnt = 0; cnt < count; cnt++) {
+		if (msm_host->pdata->clk_table[cnt] > req_clk) {
+			break;
+		} else if (msm_host->pdata->clk_table[cnt] == req_clk) {
+			sel_clk = msm_host->pdata->clk_table[cnt];
+			break;
+		} else {
+			sel_clk = msm_host->pdata->clk_table[cnt];
+		}
+	}
+	return sel_clk;
+}
+/**
+ * __sdhci_msm_set_clock - sdhci_msm clock control.
+ *
+ * Description:
+ * Implement MSM version of sdhci_set_clock.
+ * This is required since MSM controller does not
+ * use internal divider and instead directly control
+ * the GCC clock as per HW recommendation.
+ **/
+void __sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+	u16 clk;
+	unsigned long timeout;
+
+	host->mmc->actual_clock = 0;
+
+	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+
+	if (clock == 0)
+		return;
+
+	/*
+	 * MSM controller do not use clock divider.
+	 * Thus read SDHCI_CLOCK_CONTROL and only enable
+	 * clock with no divider value programmed.
+	 */
+	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+
+	clk |= SDHCI_CLOCK_INT_EN;
+	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+	/* Wait max 20 ms */
+	timeout = 20;
+	while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
+		& SDHCI_CLOCK_INT_STABLE)) {
+		if (timeout == 0) {
+			pr_err("%s: Internal clock never stabilised.\n",
+			       mmc_hostname(host->mmc));
+			return;
+		}
+		timeout--;
+		mdelay(1);
+	}
+
+	clk |= SDHCI_CLOCK_CARD_EN;
+	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+}
+
+static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+	u32 msm_clock = 0;
+	int rc = 0;
+
+	if (!clock)
+		goto out;
+
+	if (clock != msm_host->clk_rate) {
+		msm_clock = sdhci_msm_get_msm_clk_rate(host, clock);
+		rc = clk_set_rate(msm_host->clk, msm_clock);
+		if (rc) {
+			pr_err("%s: failed to set clock at rate %u, requested clock rate %u\n",
+				mmc_hostname(host->mmc), msm_clock, clock);
+			goto out;
+		}
+		msm_host->clk_rate = clock;
+		pr_debug("%s: setting clock at rate %lu\n",
+			mmc_hostname(host->mmc), clk_get_rate(msm_host->clk));
+	}
+out:
+	__sdhci_msm_set_clock(host, clock);
+}
+
 static const struct of_device_id sdhci_msm_dt_match[] = {
 	{ .compatible = "qcom,sdhci-msm-v4" },
 	{},
@@ -580,7 +681,7 @@ MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
 static const struct sdhci_ops sdhci_msm_ops = {
 	.platform_execute_tuning = sdhci_msm_execute_tuning,
 	.reset = sdhci_reset,
-	.set_clock = sdhci_set_clock,
+	.set_clock = sdhci_msm_set_clock,
 	.get_min_clock = sdhci_msm_get_min_clock,
 	.get_max_clock = sdhci_msm_get_max_clock,
 	.set_bus_width = sdhci_set_bus_width,
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, 
a Linux Foundation Collaborative Project.
#9 lore raw

PATCH v2 7/8 mmc: sdhci-msm: Add clock changes for DDR mode.

In reply to Ritesh Harjani

SDHC MSM controller need 2x clock for MCLK at GCC. Hence make required changes to have 2x clock for DDR timing modes.

---
 drivers/mmc/host/sdhci-msm.c | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)
drivers/mmc/host/sdhci-msm.c +18 -4
index 1eb5074..e68f0c9 100644
@@ -649,21 +649,35 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
-	u32 msm_clock = 0;
+	struct mmc_ios curr_ios = host->mmc->ios;
+	u32 msm_clock = clock, ddr_clock = 0;
 	int rc = 0;
 
 	if (!clock)
 		goto out;
 
-	if (clock != msm_host->clk_rate) {
-		msm_clock = sdhci_msm_get_msm_clk_rate(host, clock);
+	msm_clock = sdhci_msm_get_msm_clk_rate(host, clock);
+	if ((curr_ios.timing == MMC_TIMING_UHS_DDR50) ||
+		(curr_ios.timing == MMC_TIMING_MMC_DDR52) ||
+		(curr_ios.timing == MMC_TIMING_MMC_HS400)) {
+		/*
+		 * The SDHC requires internal clock frequency to be double the
+		 * actual clock that will be set for DDR mode. The controller
+		 * uses the faster clock(100/400MHz) for some of its parts and
+		 * send the actual required clock (50/200MHz) to the card.
+		 */
+		ddr_clock = clock * 2;
+		msm_clock = sdhci_msm_get_msm_clk_rate(host, ddr_clock);
+	}
+
+	if (msm_clock != msm_host->clk_rate) {
 		rc = clk_set_rate(msm_host->clk, msm_clock);
 		if (rc) {
 			pr_err("%s: failed to set clock at rate %u, requested clock rate %u\n",
 				mmc_hostname(host->mmc), msm_clock, clock);
 			goto out;
 		}
-		msm_host->clk_rate = clock;
+		msm_host->clk_rate = msm_clock;
 		pr_debug("%s: setting clock at rate %lu\n",
 			mmc_hostname(host->mmc), clk_get_rate(msm_host->clk));
 	}
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, 
a Linux Foundation Collaborative Project.
#10 lore raw

PATCH v2 8/8 arm64: dts: qcom: msm8916: Add ddr support to sdhc1

In reply to Ritesh Harjani

This adds mmc-ddr-1_8v support to DT for sdhc1 of msm8916.

---
 arch/arm64/boot/dts/qcom/msm8916.dtsi | 1 +
 1 file changed, 1 insertion(+)
arch/arm64/boot/dts/qcom/msm8916.dtsi +1 -0
index 5161740..514c61e 100644
@@ -390,6 +390,7 @@
 			clock-names = "core", "iface";
 			clk-rates = <400000 25000000 50000000 100000000
 					177770000>;
+			mmc-ddr-1_8v;
 			bus-width = <8>;
 			non-removable;
 			status = "disabled";
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, 
a Linux Foundation Collaborative Project.