Skip to contentSkip to conversation

mmc: fsl_esdhc: Allow all supported prescaler values

PATCH New Benoît Thébaudeau 3 participants 12 messages May 3, 2017 – May 31, 2017

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/4 mmc: fsl_esdhc: Allow all supported prescaler values

On i.MX, SYSCTL.SDCLKFS may be set to 0 in order to make the SD clock frequency prescaler divide by 1 in SDR mode. In DDR mode, the prescaler can divide by up to 512. Allow both of these settings.

The maximum SD clock frequency in High Speed mode is 50 MHz. On i.MX25, this change makes it possible to get 48 MHz from the USB PLL (240 MHz / 5 / 1) instead of only 40 MHz from the USB PLL (240 MHz / 3 / 2) or 33.25 MHz from the AHB clock (133 MHz / 2 / 2).

---
 drivers/mmc/fsl_esdhc.c | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)
drivers/mmc/fsl_esdhc.c +12 -11
index f3c6358..ca72627 100644
@@ -521,7 +521,13 @@ out:
 
 static void set_sysctl(struct mmc *mmc, uint clock)
 {
-	int div, pre_div;
+	int div = 1;
+#ifdef ARCH_MXC
+	int pre_div = 1;
+#else
+	int pre_div = 2;
+#endif
+	int ddr_pre_div = mmc->ddr_mode ? 2 : 1;
 	struct fsl_esdhc_priv *priv = mmc->priv;
 	struct fsl_esdhc *regs = priv->esdhc_regs;
 	int sdhc_clk = priv->sdhc_clk;
@@ -530,18 +536,13 @@ static void set_sysctl(struct mmc *mmc, uint clock)
 	if (clock < mmc->cfg->f_min)
 		clock = mmc->cfg->f_min;
 
-	if (sdhc_clk / 16 > clock) {
-		for (pre_div = 2; pre_div < 256; pre_div *= 2)
-			if ((sdhc_clk / pre_div) <= (clock * 16))
-				break;
-	} else
-		pre_div = 2;
+	while (sdhc_clk / (16 * pre_div * ddr_pre_div) > clock && pre_div < 256)
+		pre_div *= 2;
 
-	for (div = 1; div <= 16; div++)
-		if ((sdhc_clk / (div * pre_div)) <= clock)
-			break;
+	while (sdhc_clk / (div * pre_div * ddr_pre_div) > clock && div < 16)
+		div++;
 
-	pre_div >>= mmc->ddr_mode ? 2 : 1;
+	pre_div >>= 1;
 	div -= 1;
 
 	clk = (pre_div << 8) | (div << 4);
Signature · 1 line
2.7.4
#1 lore raw

PATCH 2/4 mx25: Fix imx_get_perclk()

imx_get_perclk() used the AHB clock as the clock source for all PER clocks, but the USB PLL output can also be a PER clock source if the corresponding PER CLK MUX bit is set in CCM.MCR.

---
 arch/arm/cpu/arm926ejs/mx25/generic.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
arch/arm/cpu/arm926ejs/mx25/generic.c +10 -1
index 0b1a8f4..f02cffb 100644
@@ -58,6 +58,14 @@ static ulong imx_get_mpllclk(void)
 	return imx_decode_pll(readl(&ccm->mpctl), fref);
 }
 
+static ulong imx_get_upllclk(void)
+{
+	struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
+	ulong fref = MXC_HCLK;
+
+	return imx_decode_pll(readl(&ccm->upctl), fref);
+}
+
 static ulong imx_get_armclk(void)
 {
 	struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
@@ -95,7 +103,8 @@ static ulong imx_get_ipgclk(void)
 static ulong imx_get_perclk(int clk)
 {
 	struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
-	ulong fref = imx_get_ahbclk();
+	ulong fref = readl(&ccm->mcr) & (1 << clk) ? imx_get_upllclk() :
+						     imx_get_ahbclk();
 	ulong div;
 
 	div = readl(&ccm->pcdr[CCM_PERCLK_REG(clk)]);
Signature · 1 line
2.7.4
#3 lore raw

PATCH 2/4 mx25: Fix imx_get_perclk()

In reply to Benoît Thébaudeau
Quoted 30 lines · Benoît Thébaudeau

imx_get_perclk() used the AHB clock as the clock source for all PER clocks, but the USB PLL output can also be a PER clock source if the corresponding PER CLK MUX bit is set in CCM.MCR.

---
 arch/arm/cpu/arm926ejs/mx25/generic.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
arch/arm/cpu/arm926ejs/mx25/generic.c +8 -0
index 0b1a8f4..f02cffb 100644
@@ -58,6 +58,14 @@ static ulong imx_get_mpllclk(void)
 	return imx_decode_pll(readl(&ccm->mpctl), fref);
 }
 
+static ulong imx_get_upllclk(void)
+{
+	struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
+	ulong fref = MXC_HCLK;
+
+	return imx_decode_pll(readl(&ccm->upctl), fref);
+}
+
 static ulong imx_get_armclk(void)
 {
 	struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;

arch/arm/cpu/arm926ejs/mx25/generic.c static ulong imx_get_ipgclk(void) · line 110

Quoted 9 lines
arch/arm/cpu/arm926ejs/mx25/generic.c +2 -1
@@ -95,7 +103,8 @@ static ulong imx_get_ipgclk(void)
 static ulong imx_get_perclk(int clk)
 {
 	struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
-	ulong fref = imx_get_ahbclk();
+	ulong fref = readl(&ccm->mcr) & (1 << clk) ? imx_get_upllclk() :
+						     imx_get_ahbclk();
 	ulong div;
 
 	div = readl(&ccm->pcdr[CCM_PERCLK_REG(clk)]);

Applied to u-boot-imx -master, thanks !

Best regards,
Stefano Babic

Signature · 5 lines
=====================================================================
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic at denx.de
=====================================================================
#4 lore raw

PATCH 3/4 mx25: Add function to set PER clocks

In reply to Benoît Thébaudeau

Introduce the imx_set_perclk() function to make it possible to set the PER clocks.

---
 arch/arm/cpu/arm926ejs/mx25/generic.c  | 19 +++++++++++++++++++
 arch/arm/include/asm/arch-mx25/clock.h |  1 +
 2 files changed, 20 insertions(+)
arch/arm/cpu/arm926ejs/mx25/generic.c +19 -0
index f02cffb..5d9bc6c 100644
@@ -113,6 +113,25 @@ static ulong imx_get_perclk(int clk)
 	return fref / div;
 }
 
+int imx_set_perclk(enum mxc_clock clk, bool from_upll, unsigned int freq)
+{
+	struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
+	ulong fref = from_upll ? imx_get_upllclk() : imx_get_ahbclk();
+	ulong div = (fref + freq - 1) / freq;
+
+	if (clk > MXC_UART_CLK || !div || --div > CCM_PERCLK_MASK)
+		return -EINVAL;
+
+	clrsetbits_le32(&ccm->pcdr[CCM_PERCLK_REG(clk)],
+			CCM_PERCLK_MASK << CCM_PERCLK_SHIFT(clk),
+			div << CCM_PERCLK_SHIFT(clk));
+	if (from_upll)
+		setbits_le32(&ccm->mcr, 1 << clk);
+	else
+		clrbits_le32(&ccm->mcr, 1 << clk);
+	return 0;
+}
+
 unsigned int mxc_get_clock(enum mxc_clock clk)
 {
 	if (clk >= MXC_CLK_NUM)
arch/arm/include/asm/arch-mx25/clock.h +1 -0
index 9fdaa9d..7753caf 100644
@@ -51,6 +51,7 @@ enum mxc_clock {
 	MXC_CLK_NUM
 };
 
+int imx_set_perclk(enum mxc_clock clk, bool from_upll, unsigned int freq);
 unsigned int mxc_get_clock(enum mxc_clock clk);
 
 #define imx_get_uartclk()	mxc_get_clock(MXC_UART_CLK)
Signature · 1 line
2.7.4
#6 lore raw

PATCH 3/4 mx25: Add function to set PER clocks

In reply to Benoît Thébaudeau
Quoted 45 lines · Benoît Thébaudeau

Introduce the imx_set_perclk() function to make it possible to set the PER clocks.

---
 arch/arm/cpu/arm926ejs/mx25/generic.c  | 19 +++++++++++++++++++
 arch/arm/include/asm/arch-mx25/clock.h |  1 +
 2 files changed, 20 insertions(+)
arch/arm/cpu/arm926ejs/mx25/generic.c +19 -0
index f02cffb..5d9bc6c 100644
@@ -113,6 +113,25 @@ static ulong imx_get_perclk(int clk)
 	return fref / div;
 }
 
+int imx_set_perclk(enum mxc_clock clk, bool from_upll, unsigned int freq)
+{
+	struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
+	ulong fref = from_upll ? imx_get_upllclk() : imx_get_ahbclk();
+	ulong div = (fref + freq - 1) / freq;
+
+	if (clk > MXC_UART_CLK || !div || --div > CCM_PERCLK_MASK)
+		return -EINVAL;
+
+	clrsetbits_le32(&ccm->pcdr[CCM_PERCLK_REG(clk)],
+			CCM_PERCLK_MASK << CCM_PERCLK_SHIFT(clk),
+			div << CCM_PERCLK_SHIFT(clk));
+	if (from_upll)
+		setbits_le32(&ccm->mcr, 1 << clk);
+	else
+		clrbits_le32(&ccm->mcr, 1 << clk);
+	return 0;
+}
+
 unsigned int mxc_get_clock(enum mxc_clock clk)
 {
 	if (clk >= MXC_CLK_NUM)
arch/arm/include/asm/arch-mx25/clock.h +0 -0
index 9fdaa9d..7753caf 100644

arch/arm/include/asm/arch-mx25/clock.h enum mxc_clock { · line 57

Quoted 7 lines
arch/arm/include/asm/arch-mx25/clock.h +1 -0
@@ -51,6 +51,7 @@ enum mxc_clock {
 	MXC_CLK_NUM
 };
 
+int imx_set_perclk(enum mxc_clock clk, bool from_upll, unsigned int freq);
 unsigned int mxc_get_clock(enum mxc_clock clk);
 
 #define imx_get_uartclk()	mxc_get_clock(MXC_UART_CLK)

Applied to u-boot-imx -master, thanks !

Best regards,
Stefano Babic

Signature · 5 lines
=====================================================================
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic at denx.de
=====================================================================
#7 lore raw

PATCH 4/4 mx25pdk: Set the eSDHC PER clock to 48 MHz

In reply to Benoît Thébaudeau

The maximum SD clock frequency in High Speed mode is 50 MHz. This change makes it possible to get 48 MHz from the USB PLL (240 MHz / 5 / 1) instead of the previous 33.25 MHz from the AHB clock (133 MHz / 2 / 2).

---
 board/freescale/mx25pdk/mx25pdk.c | 6 ++++++
 1 file changed, 6 insertions(+)
board/freescale/mx25pdk/mx25pdk.c +6 -0
index 788d3c3..cab769c 100644
@@ -175,6 +175,12 @@ int board_mmc_init(bd_t *bis)
 
 	imx_iomux_v3_setup_multiple_pads(sdhc1_pads, ARRAY_SIZE(sdhc1_pads));
 
+	/*
+	 * Set the eSDHC1 PER clock to the maximum frequency lower than or equal
+	 * to 50 MHz that can be obtained, which requires to use UPLL as the
+	 * clock source. This actually gives 48 MHz.
+	 */
+	imx_set_perclk(MXC_ESDHC1_CLK, true, 50000000);
 	esdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC1_CLK);
 	return fsl_esdhc_initialize(bis, &esdhc_cfg[0]);
 }
Signature · 1 line
2.7.4
#9 lore raw

PATCH 4/4 mx25pdk: Set the eSDHC PER clock to 48 MHz

In reply to Benoît Thébaudeau
Quoted 17 lines · Benoît Thébaudeau

The maximum SD clock frequency in High Speed mode is 50 MHz. This change makes it possible to get 48 MHz from the USB PLL (240 MHz / 5 / 1) instead of the previous 33.25 MHz from the AHB clock (133 MHz / 2 / 2).

---
 board/freescale/mx25pdk/mx25pdk.c | 6 ++++++
 1 file changed, 6 insertions(+)
board/freescale/mx25pdk/mx25pdk.c +0 -0
index 788d3c3..cab769c 100644
@@ -175,6 +175,12 @@ int board_mmc_init(bd_t *bis)
 
 	imx_iomux_v3_setup_multiple_pads(sdhc1_pads, ARRAY_SIZE(sdhc1_pads));

board/freescale/mx25pdk/mx25pdk.c int board_mmc_init(bd_t *bis) · line 186

Quoted 10 lines
board/freescale/mx25pdk/mx25pdk.c +6 -0
 
+	/*
+	 * Set the eSDHC1 PER clock to the maximum frequency lower than or equal
+	 * to 50 MHz that can be obtained, which requires to use UPLL as the
+	 * clock source. This actually gives 48 MHz.
+	 */
+	imx_set_perclk(MXC_ESDHC1_CLK, true, 50000000);
 	esdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC1_CLK);
 	return fsl_esdhc_initialize(bis, &esdhc_cfg[0]);
 }

Applied to u-boot-imx -master, thanks !

Best regards,
Stefano Babic

Signature · 5 lines
=====================================================================
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic at denx.de
=====================================================================
#10 lore raw

PATCH 1/4 mmc: fsl_esdhc: Allow all supported prescaler values

In reply to Benoît Thébaudeau
Quoted 10 lines · Benoît Thébaudeau

On i.MX, SYSCTL.SDCLKFS may be set to 0 in order to make the SD clock frequency prescaler divide by 1 in SDR mode. In DDR mode, the prescaler can divide by up to 512. Allow both of these settings.

The maximum SD clock frequency in High Speed mode is 50 MHz. On i.MX25, this change makes it possible to get 48 MHz from the USB PLL (240 MHz / 5 / 1) instead of only 40 MHz from the USB PLL (240 MHz / 3 / 2) or 33.25 MHz from the AHB clock (133 MHz / 2 / 2).

#11 lore raw

PATCH 1/4 mmc: fsl_esdhc: Allow all supported prescaler values

In reply to Benoît Thébaudeau
Quoted 48 lines · Benoît Thébaudeau

On i.MX, SYSCTL.SDCLKFS may be set to 0 in order to make the SD clock frequency prescaler divide by 1 in SDR mode. In DDR mode, the prescaler can divide by up to 512. Allow both of these settings.

The maximum SD clock frequency in High Speed mode is 50 MHz. On i.MX25, this change makes it possible to get 48 MHz from the USB PLL (240 MHz / 5 / 1) instead of only 40 MHz from the USB PLL (240 MHz / 3 / 2) or 33.25 MHz from the AHB clock (133 MHz / 2 / 2).

---
 drivers/mmc/fsl_esdhc.c | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)
drivers/mmc/fsl_esdhc.c +9 -8
index f3c6358..ca72627 100644
@@ -521,7 +521,13 @@ out:
 
 static void set_sysctl(struct mmc *mmc, uint clock)
 {
-	int div, pre_div;
+	int div = 1;
+#ifdef ARCH_MXC
+	int pre_div = 1;
+#else
+	int pre_div = 2;
+#endif
+	int ddr_pre_div = mmc->ddr_mode ? 2 : 1;
 	struct fsl_esdhc_priv *priv = mmc->priv;
 	struct fsl_esdhc *regs = priv->esdhc_regs;
 	int sdhc_clk = priv->sdhc_clk;
@@ -530,18 +536,13 @@ static void set_sysctl(struct mmc *mmc, uint clock)
 	if (clock < mmc->cfg->f_min)
 		clock = mmc->cfg->f_min;
 
-	if (sdhc_clk / 16 > clock) {
-		for (pre_div = 2; pre_div < 256; pre_div *= 2)
-			if ((sdhc_clk / pre_div) <= (clock * 16))
-				break;
-	} else
-		pre_div = 2;
+	while (sdhc_clk / (16 * pre_div * ddr_pre_div) > clock && pre_div < 256)
+		pre_div *= 2;
 
-	for (div = 1; div <= 16; div++)

drivers/mmc/fsl_esdhc.c static void set_sysctl(struct mmc *mmc, uint clock) · line 548

Quoted 10 lines
drivers/mmc/fsl_esdhc.c +3 -3
-		if ((sdhc_clk / (div * pre_div)) <= clock)
-			break;
+	while (sdhc_clk / (div * pre_div * ddr_pre_div) > clock && div < 16)
+		div++;
 
-	pre_div >>= mmc->ddr_mode ? 2 : 1;
+	pre_div >>= 1;
 	div -= 1;
 
 	clk = (pre_div << 8) | (div << 4);

Applied to u-boot-imx -master, thanks !

Best regards,
Stefano Babic

Signature · 5 lines
=====================================================================
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic at denx.de
=====================================================================