imx: mx7: change sdhc clk to 392M
PATCH 1/5 imx: mx7: change sdhc clk to 392M
Change sdhc clk to 392M.
Prepare support for SDR104 and HS200.
--- arch/arm/mach-imx/mx7/clock.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/arm/mach-imx/mx7/clock.c +3 -3
@@ -561,17 +561,17 @@ static void init_clk_esdhc(void)/* 196: 392/2 */ target =CLK_ROOT_ON |USDHC1_CLK_ROOT_FROM_PLL_SYS_PFD0_392M_CLK |CLK_ROOT_PRE_DIV (CLK_ROOT_PRE_DIV1 ) | -CLK_ROOT_POST_DIV (CLK_ROOT_POST_DIV2 ); +CLK_ROOT_POST_DIV (CLK_ROOT_POST_DIV1 );clock_set_target_val (USDHC1_CLK_ROOT , target); target =CLK_ROOT_ON |USDHC1_CLK_ROOT_FROM_PLL_SYS_PFD0_392M_CLK |CLK_ROOT_PRE_DIV (CLK_ROOT_PRE_DIV1 ) | -CLK_ROOT_POST_DIV (CLK_ROOT_POST_DIV2 ); +CLK_ROOT_POST_DIV (CLK_ROOT_POST_DIV1 );clock_set_target_val (USDHC2_CLK_ROOT , target); target =CLK_ROOT_ON |USDHC1_CLK_ROOT_FROM_PLL_SYS_PFD0_392M_CLK |CLK_ROOT_PRE_DIV (CLK_ROOT_PRE_DIV1 ) | -CLK_ROOT_POST_DIV (CLK_ROOT_POST_DIV2 ); +CLK_ROOT_POST_DIV (CLK_ROOT_POST_DIV1 );clock_set_target_val (USDHC3_CLK_ROOT , target);/* enable the clock gate */
Signature · 1 line
2.14.1
PATCH 2/5 mmc: fsl_esdhc: add strobe and tuning entry
Add entries that will be used for tuning control. The whole layout not changed, just expand reserved3[84] and rename other reservedx in sequence.
--- drivers/mmc/fsl_esdhc.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-)
drivers/mmc/fsl_esdhc.c +12 -8
@@ -61,23 +61,27 @@ struct fsl_esdhc {uint dllctrl;uint dllstat;uint clktunectrlstatus; -char reserved3[84 ]; +char reserved3[4 ]; +uint strobe_dllctrl; +uint strobe_dllstat; +char reserved4[72 ];uint vendorspec;uint mmcboot;uint vendorspec2; -char reserved4[48 ]; +uint tuning_ctrl;/* on i.MX6/7/8 */ +char reserved5[44 ];uint hostver;/* Host controller version register */ -char reserved5[4 ];/* reserved */ -uint dmaerraddr;/* DMA error address register */ char reserved6[4 ];/* reserved */ -uint dmaerrattr;/* DMA error attribute register */ +uint dmaerraddr;/* DMA error address register */ char reserved7[4 ];/* reserved */ +uint dmaerrattr;/* DMA error attribute register */ +char reserved8[4 ];/* reserved */ uint hostcapblt2;/* Host controller capabilities register 2 */ -char reserved8[8 ];/* reserved */ +char reserved9[8 ];/* reserved */ uint tcr;/* Tuning control register */ -char reserved9[28 ];/* reserved */ +char reserved10[28 ];/* reserved */ uint sddirctl;/* SD direction control register */ -char reserved10[712 ];/* reserved */ +char reserved11[712 ];/* reserved */ uint scr;/* eSDHC control register */ };
Signature · 1 line
2.14.1
PATCH 3/5 ARM: dts: add pinmux and tuning settings for HS200/SDR104
In reply to Peng FanThe pinmux and tuning settings are from
https://source.codeaurora.org/external/imx/linux-imx/tree/arch/
arm/boot/dts/imx7s.dtsi?h=imx_4.9.11_1.0.0_ga
https://source.codeaurora.org/external/imx/linux-imx/tree/arch/
arm/boot/dts/imx7d-sdb.dts?h=imx_4.9.11_1.0.0_ga
To support HS200 and SDR104, we need change pinmux settings dynamically. And configure tuning step and start tuning tap, otherwise you may see tuning failure.
--- arch/arm/dts/imx7d-sdb.dts | 88 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+)
arch/arm/dts/imx7d-sdb.dts +88 -0
@@ -134,6 +134,28 @@ >; }; + pinctrl_usdhc1_100mhz: usdhc1grp_100mhz { + fsl,pins = < + MX7D_PAD_SD1_CMD__SD1_CMD 0x5a + MX7D_PAD_SD1_CLK__SD1_CLK 0x1a + MX7D_PAD_SD1_DATA0__SD1_DATA0 0x5a + MX7D_PAD_SD1_DATA1__SD1_DATA1 0x5a + MX7D_PAD_SD1_DATA2__SD1_DATA2 0x5a + MX7D_PAD_SD1_DATA3__SD1_DATA3 0x5a + >; + }; + + pinctrl_usdhc1_200mhz: usdhc1grp_200mhz { + fsl,pins = < + MX7D_PAD_SD1_CMD__SD1_CMD 0x5b + MX7D_PAD_SD1_CLK__SD1_CLK 0x1b + MX7D_PAD_SD1_DATA0__SD1_DATA0 0x5b + MX7D_PAD_SD1_DATA1__SD1_DATA1 0x5b + MX7D_PAD_SD1_DATA2__SD1_DATA2 0x5b + MX7D_PAD_SD1_DATA3__SD1_DATA3 0x5b + >; + }; + pinctrl_usdhc2: usdhc2grp { fsl,pins = < MX7D_PAD_SD2_CMD__SD2_CMD 0x59
@@ -147,6 +169,28 @@ >; }; + pinctrl_usdhc2_100mhz: usdhc2grp_100mhz { + fsl,pins = < + MX7D_PAD_SD2_CMD__SD2_CMD 0x5a + MX7D_PAD_SD2_CLK__SD2_CLK 0x1a + MX7D_PAD_SD2_DATA0__SD2_DATA0 0x5a + MX7D_PAD_SD2_DATA1__SD2_DATA1 0x5a + MX7D_PAD_SD2_DATA2__SD2_DATA2 0x5a + MX7D_PAD_SD2_DATA3__SD2_DATA3 0x5a + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2grp_200mhz { + fsl,pins = < + MX7D_PAD_SD2_CMD__SD2_CMD 0x5b + MX7D_PAD_SD2_CLK__SD2_CLK 0x1b + MX7D_PAD_SD2_DATA0__SD2_DATA0 0x5b + MX7D_PAD_SD2_DATA1__SD2_DATA1 0x5b + MX7D_PAD_SD2_DATA2__SD2_DATA2 0x5b + MX7D_PAD_SD2_DATA3__SD2_DATA3 0x5b + >; + }; + pinctrl_usdhc3: usdhc3grp { fsl,pins = < MX7D_PAD_SD3_CMD__SD3_CMD 0x59
@@ -162,6 +206,38 @@ MX7D_PAD_SD3_STROBE__SD3_STROBE 0x19 >; }; + + pinctrl_usdhc3_100mhz: usdhc3grp_100mhz { + fsl,pins = < + MX7D_PAD_SD3_CMD__SD3_CMD 0x5a + MX7D_PAD_SD3_CLK__SD3_CLK 0x1a + MX7D_PAD_SD3_DATA0__SD3_DATA0 0x5a + MX7D_PAD_SD3_DATA1__SD3_DATA1 0x5a + MX7D_PAD_SD3_DATA2__SD3_DATA2 0x5a + MX7D_PAD_SD3_DATA3__SD3_DATA3 0x5a + MX7D_PAD_SD3_DATA4__SD3_DATA4 0x5a + MX7D_PAD_SD3_DATA5__SD3_DATA5 0x5a + MX7D_PAD_SD3_DATA6__SD3_DATA6 0x5a + MX7D_PAD_SD3_DATA7__SD3_DATA7 0x5a + MX7D_PAD_SD3_STROBE__SD3_STROBE 0x1a + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3grp_200mhz { + fsl,pins = < + MX7D_PAD_SD3_CMD__SD3_CMD 0x5b + MX7D_PAD_SD3_CLK__SD3_CLK 0x1b + MX7D_PAD_SD3_DATA0__SD3_DATA0 0x5b + MX7D_PAD_SD3_DATA1__SD3_DATA1 0x5b + MX7D_PAD_SD3_DATA2__SD3_DATA2 0x5b + MX7D_PAD_SD3_DATA3__SD3_DATA3 0x5b + MX7D_PAD_SD3_DATA4__SD3_DATA4 0x5b + MX7D_PAD_SD3_DATA5__SD3_DATA5 0x5b + MX7D_PAD_SD3_DATA6__SD3_DATA6 0x5b + MX7D_PAD_SD3_DATA7__SD3_DATA7 0x5b + MX7D_PAD_SD3_STROBE__SD3_STROBE 0x1b + >; + }; }; };
@@ -287,23 +363,35 @@ &usdhc1 { pinctrl-names = "default", "state_100mhz", "state_200mhz"; pinctrl-0 = <&pinctrl_usdhc1>, <&pinctrl_usdhc1_gpio>; + pinctrl-1 = <&pinctrl_usdhc1_100mhz>, <&pinctrl_usdhc1_gpio>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>, <&pinctrl_usdhc1_gpio>; cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>; wp-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>; vmmc-supply = <®_sd1_vmmc>; + fsl,tuning-start-tap = <20>; + fsl,tuning-step= <2>; status = "okay"; }; &usdhc2 { pinctrl-names = "default", "state_100mhz", "state_200mhz"; pinctrl-0 = <&pinctrl_usdhc2>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>; non-removable; + fsl,tuning-start-tap = <20>; + fsl,tuning-step= <2>; status = "okay"; }; &usdhc3 { pinctrl-names = "default", "state_100mhz", "state_200mhz"; pinctrl-0 = <&pinctrl_usdhc3>; + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; bus-width = <8>; non-removable; + fsl,tuning-start-tap = <20>; + fsl,tuning-step= <2>; status = "okay"; };
Signature · 1 line
2.14.1
PATCH 4/5 mmc: fsl_esdhc: support SDR104 and HS200
In reply to Peng FanIntroduce SDR104 and HS200 support
The implementation takes linux kernel sdhci.c and sdhci-esdhc-imx.c as reference.
- Implement esdhc_change_pinstate to dynamically change pad settings
- Implement esdhc_set_timing
- Implement esdhc_set_voltage to switch voltage
- Implement fsl_esdhc_execute_tuning to execute time process
- Enlarge the cfg->f_max to 200MHz.
- Parse fsl,tuning-step, fsl,tuning-start-tap and fsl,strobe-dll-delay-target from device tree.
- Parse no-1-8-v property
- Introduce esdhc_soc_data to indicate the flags and caps
--- drivers/mmc/fsl_esdhc.c | 359 +++++++++++++++++++++++++++++++++++++++++++++++- include/fsl_esdhc.h | 47 +++++++ 2 files changed, 401 insertions(+), 5 deletions(-)
drivers/mmc/fsl_esdhc.c +354 -5
@@ -23,6 +23,7 @@#include <asm/io.h> #include <dm.h> #include <asm-generic/gpio.h> +#include <dm/pinctrl.h> DECLARE_GLOBAL_DATA_PTR ;
@@ -90,6 +91,11 @@ struct fsl_esdhc_plat {struct mmc mmc; }; +struct esdhc_soc_data { +u32 flags; +u32 caps; +}; +/** * struct fsl_esdhc_priv *
@@ -103,12 +109,20 @@ struct fsl_esdhc_plat {* @non_removable: 0: removable; 1: non-removable * @wp_enable: 1: enable checking wp; 0: no check * @vs18_enable: 1: use 1.8V voltage; 0: use 3.3V +* @flags: ESDHC_FLAG_xx in include/fsl_esdhc.h +* @caps: controller capabilities +* @tuning_step: tuning step setting in tuning_ctrl register +* @start_tuning_tap: the start point for tuning in tuning_ctrl register +* @strobe_dll_delay_target: settings in strobe_dllctrl +* @signal_voltage: indicating the current voltage * @cd_gpio: gpio for card detection * @wp_gpio: gpio for write protection */ struct fsl_esdhc_priv {struct fsl_esdhc *esdhc_regs;unsigned int sdhc_clk; +unsigned int clock; +unsigned int mode;unsigned int bus_width;#if !CONFIG_IS_ENABLED (BLK )struct mmc *mmc;
@@ -117,6 +131,16 @@ struct fsl_esdhc_priv {int non_removable;int wp_enable;int vs18_enable; +u32 flags; +u32 caps; +u32 tuning_step; +u32 tuning_start_tap; +u32 strobe_dll_delay_target; +u32 signal_voltage; +#if IS_ENABLED (CONFIG_DM_REGULATOR ) +struct udevice *vqmmc_dev; +struct udevice *vmmc_dev; +#endif #ifdef CONFIG_DM_GPIO struct gpio_desc cd_gpio;struct gpio_desc wp_gpio;
@@ -364,6 +388,7 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc,int err =0 ;uint xfertyp;uint irqstat; +u32 flags;struct fsl_esdhc *regs = priv->esdhc_regs;#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111
@@ -417,8 +442,15 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc,esdhc_write32 (®s->xfertyp, xfertyp);#endif +if ((cmd->cmdidx ==MMC_CMD_SEND_TUNING_BLOCK ) || + (cmd->cmdidx ==MMC_CMD_SEND_TUNING_BLOCK_HS200 )) { + flags =IRQSTAT_BRR ; + }else { + flags =IRQSTAT_CC |IRQSTAT_CTOE ; + } +/* Wait for the command to complete */ -while (!(esdhc_read32 (®s->irqstat) & (IRQSTAT_CC |IRQSTAT_CTOE ))) +while (!(esdhc_read32 (®s->irqstat) & flags)) ; irqstat =esdhc_read32 (®s->irqstat);
@@ -480,6 +512,12 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO esdhc_pio_read_write(priv, data); #else + flags = DATA_COMPLETE; + if ((cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK) || + (cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200)) { + flags = IRQSTAT_BRR; + } + do { irqstat = esdhc_read32(®s->irqstat);
@@ -492,7 +530,7 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, err = -ECOMM ; goto out; } - }while ((irqstat &DATA_COMPLETE ) !=DATA_COMPLETE ); + }while ((irqstat & flags) != flags);/* * Need invalidate the dcache here again to avoid any
@@ -573,6 +611,7 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock)esdhc_setbits32 (®s->sysctl,SYSCTL_PEREN |SYSCTL_CKEN );#endif + priv->clock = clock; }#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK
@@ -604,9 +643,233 @@ static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) }#endif +#ifdef MMC_SUPPORTS_TUNING +static int esdhc_change_pinstate (struct udevice *dev) +{ +struct fsl_esdhc_priv *priv =dev_get_priv (dev); +int ret; + +switch (priv->mode) { +case UHS_SDR50 : +case UHS_DDR50 : + ret =pinctrl_select_state (dev,"state_100mhz" ); +break ; +case UHS_SDR104 : +case MMC_HS_200 : + ret =pinctrl_select_state (dev,"state_200mhz" ); +break ; +default : + ret =pinctrl_select_state (dev,"default" ); +break ; + } + +if (ret) +printf ("%s %d error\n" , __func__, priv->mode); + +return ret; +} + +static void esdhc_reset_tuning (struct mmc *mmc) +{ +struct fsl_esdhc_priv *priv =dev_get_priv (mmc->dev); +struct fsl_esdhc *regs = priv->esdhc_regs; + +if (priv->flags &ESDHC_FLAG_USDHC ) { +if (priv->flags &ESDHC_FLAG_STD_TUNING ) { +esdhc_clrbits32 (®s->autoc12err, +MIX_CTRL_SMPCLK_SEL | +MIX_CTRL_EXE_TUNE ); + } + } +} + +static int esdhc_set_timing (struct mmc *mmc) +{ +struct fsl_esdhc_priv *priv =dev_get_priv (mmc->dev); +struct fsl_esdhc *regs = priv->esdhc_regs; +u32 m; + + m =readl (®s->mixctrl); + m &= ~(MIX_CTRL_DDREN |MIX_CTRL_HS400_EN ); + +switch (mmc->selected_mode) { +case MMC_LEGACY : +case SD_LEGACY : +esdhc_reset_tuning (mmc); +break ; +case MMC_HS : +case MMC_HS_52 : +case MMC_HS_200 : +case SD_HS : +case UHS_SDR12 : +case UHS_SDR25 : +case UHS_SDR50 : +case UHS_SDR104 : +writel (m, ®s->mixctrl); +break ; +case UHS_DDR50 : +case MMC_DDR_52 : + m |=MIX_CTRL_DDREN ; +writel (m, ®s->mixctrl); +break ; +default : +printf ("Not supported %d\n" , mmc->selected_mode); +break ; + } + + priv->mode = mmc->selected_mode; + +return esdhc_change_pinstate (mmc->dev); +} + +static int esdhc_set_voltage (struct mmc *mmc) +{ +struct fsl_esdhc_priv *priv =dev_get_priv (mmc->dev); +struct fsl_esdhc *regs = priv->esdhc_regs; +int ret; + + priv->signal_voltage = mmc->signal_voltage; +switch (mmc->signal_voltage) { +case MMC_SIGNAL_VOLTAGE_330 : +if (priv->vs18_enable) +return -EIO ; +if (!IS_ERR_OR_NULL (priv->vqmmc_dev)) { + ret =regulator_set_value (priv->vqmmc_dev,3300000 ); +if (ret) { +printf ("Setting to 3.3V error" ); +return -EIO ; + } +/* Wait for 5ms */ +mdelay (5 ); + } + +esdhc_clrbits32 (®s->vendorspec,ESDHC_VENDORSPEC_VSELECT ); +if (!(esdhc_read32 (®s->vendorspec) & +ESDHC_VENDORSPEC_VSELECT )) +return 0 ; + +return -EAGAIN ; +case MMC_SIGNAL_VOLTAGE_180 : +if (!IS_ERR_OR_NULL (priv->vqmmc_dev)) { + ret =regulator_set_value (priv->vqmmc_dev,1800000 ); +if (ret) { +printf ("Setting to 1.8V error" ); +return -EIO ; + } + } +esdhc_setbits32 (®s->vendorspec,ESDHC_VENDORSPEC_VSELECT ); +if (esdhc_read32 (®s->vendorspec) &ESDHC_VENDORSPEC_VSELECT ) +return 0 ; + +return -EAGAIN ; +case MMC_SIGNAL_VOLTAGE_120 : +return -ENOTSUPP ; +default : +return 0 ; + } +} + +static void esdhc_stop_tuning (struct mmc *mmc) +{ +struct mmc_cmd cmd; + + cmd.cmdidx =MMC_CMD_STOP_TRANSMISSION ; + cmd.cmdarg =0 ; + cmd.resp_type = MMC_RSP_R1b; + +dm_mmc_send_cmd (mmc->dev, &cmd,NULL ); +} + +static int fsl_esdhc_execute_tuning (struct udevice *dev,uint32_t opcode) +{ +struct fsl_esdhc_plat *plat =dev_get_platdata (dev); +struct fsl_esdhc_priv *priv =dev_get_priv (dev); +struct fsl_esdhc *regs = priv->esdhc_regs; +struct mmc *mmc = &plat->mmc; +u32 irqstaten =readl (®s->irqstaten); +u32 irqsigen =readl (®s->irqsigen); +int i, ret = -ETIMEDOUT ; +u32 v, m; + +/* clock tuning is not needed for upto 52MHz */ +if (mmc->clock <=52000000 ) +return 0 ; + +/* This is readw/writew SDHCI_HOST_CONTROL2 when tuning */ +if (priv->flags &ESDHC_FLAG_STD_TUNING ) { + v =readl (®s->autoc12err); + m =readl (®s->mixctrl); + v &= ~MIX_CTRL_SMPCLK_SEL ; + m &= ~MIX_CTRL_FBCLK_SEL ; + m &= ~MIX_CTRL_AUTO_TUNE_EN ; + + v |=MIX_CTRL_EXE_TUNE ; + m |=MIX_CTRL_FBCLK_SEL ; + m |=MIX_CTRL_AUTO_TUNE_EN ; + +writel (v, ®s->autoc12err); +writel (m, ®s->mixctrl); + } + +/* sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); */ + v =readl (®s->mixctrl); + v =MIX_CTRL_DTDSEL_READ | (v & ~MIX_CTRL_SDHCI_MASK ); +writel (v, ®s->mixctrl); + +writel (IRQSTATEN_BRR , ®s->irqstaten); +writel (IRQSTATEN_BRR , ®s->irqsigen); + +for (i =0 ; i <40 ; i++) { +u32 ctrl; + +if (opcode ==MMC_CMD_SEND_TUNING_BLOCK_HS200 ) { +if (mmc->bus_width ==8 ) +writel (0x7080 , ®s->blkattr); +else if (mmc->bus_width ==4 ) +writel (0x7040 , ®s->blkattr); + }else { +writel (0x7040 , ®s->blkattr); + } + +/* sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE) */ + v =readl (®s->mixctrl); + v =MIX_CTRL_DTDSEL_READ | (v & ~MIX_CTRL_SDHCI_MASK ); +writel (v, ®s->mixctrl); + +/* We are using STD tuning, no need to check return value */ +mmc_send_tuning (mmc, opcode,NULL ); + + ctrl =readl (®s->autoc12err); +if ((!(ctrl &MIX_CTRL_EXE_TUNE )) && + (ctrl &MIX_CTRL_SMPCLK_SEL )) { +/* +* need to wait some time, make sure sd/mmc fininsh +* send out tuning data, otherwise, the sd/mmc can't +* response to any command when the card still out +* put the tuning data. +*/ +mdelay (1 ); + ret =0 ; +break ; + } + +/* Add 1ms delay for SD and eMMC */ +mdelay (1 ); + } + +writel (irqstaten, ®s->irqstaten); +writel (irqsigen, ®s->irqsigen); + +esdhc_stop_tuning (mmc); + +return ret; +} +#endif +static int esdhc_set_ios_common (struct fsl_esdhc_priv *priv,struct mmc *mmc) {struct fsl_esdhc *regs = priv->esdhc_regs; +int ret__maybe_unused ;#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK /* Select to use peripheral clock */
@@ -615,7 +878,41 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)esdhc_clock_control (priv, true);#endif /* Set the clock speed */ -set_sysctl (priv, mmc, mmc->clock); +if (priv->clock != mmc->clock) +set_sysctl (priv, mmc, mmc->clock); + +#ifdef MMC_SUPPORTS_TUNING +if (mmc->clk_disable) { +#ifdef CONFIG_FSL_USDHC +esdhc_clrbits32 (®s->vendorspec,VENDORSPEC_CKEN ); +#else +esdhc_clrbits32 (®s->sysctl,SYSCTL_CKEN ); +#endif + }else { +#ifdef CONFIG_FSL_USDHC +esdhc_setbits32 (®s->vendorspec,VENDORSPEC_PEREN | +VENDORSPEC_CKEN ); +#else +esdhc_setbits32 (®s->sysctl,SYSCTL_PEREN |SYSCTL_CKEN ); +#endif + } + +if (priv->mode != mmc->selected_mode) { + ret =esdhc_set_timing (mmc); +if (ret) { +printf ("esdhc_set_timing error %d\n" , ret); +return ret; + } + } + +if (priv->signal_voltage != mmc->signal_voltage) { + ret =esdhc_set_voltage (mmc); +if (ret) { +printf ("esdhc_set_voltage error %d\n" , ret); +return ret; + } + } +#endif /* Set the bus width */ esdhc_clrbits32 (®s->proctl,PROCTL_DTW_4 |PROCTL_DTW_8 );
@@ -790,6 +1087,10 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv,#ifndef CONFIG_FSL_USDHC esdhc_setbits32 (®s->sysctl,SYSCTL_PEREN |SYSCTL_HCKEN |SYSCTL_IPGEN |SYSCTL_CKEN ); +/* Clearing tuning bits in case ROM has set it already */ +esdhc_write32 (®s->mixctrl,0 ); +esdhc_write32 (®s->autoc12err,0 ); +esdhc_write32 (®s->clktunectrlstatus,0 );#else esdhc_setbits32 (®s->vendorspec,VENDORSPEC_PEREN |VENDORSPEC_HCKEN |VENDORSPEC_IPGEN |VENDORSPEC_CKEN );
@@ -863,11 +1164,27 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv, cfg->host_caps &= ~MMC_MODE_8BIT ;#endif + cfg->host_caps |= priv->caps; + cfg->f_min =400000 ; - cfg->f_max =min (priv->sdhc_clk, (u32 )52000000 ); + cfg->f_max =min (priv->sdhc_clk, (u32 )200000000 ); cfg->b_max =CONFIG_SYS_MMC_MAX_BLK_COUNT ; +writel (0 , ®s->dllctrl); +if (priv->flags &ESDHC_FLAG_USDHC ) { +if (priv->flags &ESDHC_FLAG_STD_TUNING ) { +u32 val =readl (®s->tuning_ctrl); + + val |=ESDHC_STD_TUNING_EN ; + val &= ~ESDHC_TUNING_START_TAP_MASK ; + val |= priv->tuning_start_tap; + val &= ~ESDHC_TUNING_STEP_MASK ; + val |= (priv->tuning_step) <<ESDHC_TUNING_STEP_SHIFT ; +writel (val, ®s->tuning_ctrl); + } + } +return 0 ; }
@@ -1026,6 +1343,10 @@ static int fsl_esdhc_probe(struct udevice *dev)struct mmc_uclass_priv *upriv =dev_get_uclass_priv (dev);struct fsl_esdhc_plat *plat =dev_get_platdata (dev);struct fsl_esdhc_priv *priv =dev_get_priv (dev); +const void *fdt = gd->fdt_blob; +int node =dev_of_offset (dev); +struct esdhc_soc_data *data = + (struct esdhc_soc_data *)dev_get_driver_data (dev);#ifdef CONFIG_DM_REGULATOR struct udevice *vqmmc_dev;#endif
@@ -1040,6 +1361,11 @@ static int fsl_esdhc_probe(struct udevice *dev) priv->esdhc_regs = (struct fsl_esdhc *)addr; priv->dev = dev; + priv->mode =-1 ; +if (data) { + priv->flags = data->flags; + priv->caps = data->caps; + } val =dev_read_u32_default (dev,"bus-width" ,-1 );if (val ==8 )
@@ -1049,6 +1375,15 @@ static int fsl_esdhc_probe(struct udevice *dev)else priv->bus_width =1 ; + val =fdtdec_get_int (fdt, node,"fsl,tuning-step" ,1 ); + priv->tuning_step = val; + val =fdtdec_get_int (fdt, node,"fsl,tuning-start-tap" , +ESDHC_TUNING_START_TAP_DEFAULT ); + priv->tuning_start_tap = val; + val =fdtdec_get_int (fdt, node,"fsl,strobe-dll-delay-target" , +ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT ); + priv->strobe_dll_delay_target = val; +if (dev_read_bool (dev,"non-removable" )) { priv->non_removable =1 ; }else {
@@ -1090,6 +1425,9 @@ static int fsl_esdhc_probe(struct udevice *dev) }#endif +if (fdt_get_property (fdt, node,"no-1-8-v" ,NULL )) + priv->caps &= ~(UHS_CAPS |MMC_MODE_HS200 ); +/* * TODO: * Because lack of clk driver, if SDHC clk is not enabled,
@@ -1162,15 +1500,26 @@ static const struct dm_mmc_ops fsl_esdhc_ops = { .get_cd = fsl_esdhc_get_cd, .send_cmd = fsl_esdhc_send_cmd, .set_ios = fsl_esdhc_set_ios, +#ifdef MMC_SUPPORTS_TUNING + .execute_tuning = fsl_esdhc_execute_tuning, +#endif };#endif +static struct esdhc_soc_data usdhc_imx7d_data = { + .flags =ESDHC_FLAG_USDHC |ESDHC_FLAG_STD_TUNING + |ESDHC_FLAG_HAVE_CAP1 |ESDHC_FLAG_HS200 + |ESDHC_FLAG_HS400 , + .caps =UHS_CAPS |MMC_MODE_HS200 | MMC_MODE_DDR_52MHz | + MMC_MODE_HS_52MHz |MMC_MODE_HS , +}; +static const struct udevice_id fsl_esdhc_ids[] = { { .compatible ="fsl,imx6ul-usdhc" , }, { .compatible ="fsl,imx6sx-usdhc" , }, { .compatible ="fsl,imx6sl-usdhc" , }, { .compatible ="fsl,imx6q-usdhc" , }, - { .compatible ="fsl,imx7d-usdhc" , }, + { .compatible ="fsl,imx7d-usdhc" , .data = (ulong)&usdhc_imx7d_data,}, { .compatible ="fsl,imx7ulp-usdhc" , }, { .compatible ="fsl,esdhc" , }, {/* sentinel */ }
include/fsl_esdhc.h +47 -0
59 lines not on this page · raw message
Signature · 1 line
2.14.1
PATCH 4/5 mmc: fsl_esdhc: support SDR104 and HS200
Quoted 93 lines · Peng Fan
Introduce SDR104 and HS200 support
The implementation takes linux kernelsdhci.candsdhci-esdhc-imx.cas reference.
- Implementesdhc_change_pinstateto dynamically change pad settings
- Implementesdhc_set_timing
- Implementesdhc_set_voltageto switch voltage
- Implementfsl_esdhc_execute_tuningto execute time process
- Enlarge thecfg->f_maxto 200MHz.
- Parse fsl,tuning-step, fsl,tuning-start-tap and fsl,strobe-dll-delay-target from device tree.
- Parse no-1-8-v property
- Introduceesdhc_soc_datato indicate the flags and capsSigned-off-by Peng Fan <[email protected]>Cc Stefano Babic <[email protected]>Cc Fabio Estevam <[email protected]>Cc Jaehoon Chung <[email protected]>--- drivers/mmc/fsl_esdhc.c | 359 +++++++++++++++++++++++++++++++++++++++++++++++- include/fsl_esdhc.h | 47 +++++++ 2 files changed, 401 insertions(+), 5 deletions(-)drivers/mmc/fsl_esdhc.c +25
-0@@ -23,6 +23,7 @@#include <asm/io.h> #include <dm.h> #include <asm-generic/gpio.h> +#include <dm/pinctrl.h> DECLARE_GLOBAL_DATA_PTR ;@@ -90,6 +91,11 @@ struct fsl_esdhc_plat {struct mmc mmc; }; +struct esdhc_soc_data { +u32 flags; +u32 caps; +}; +/** * struct fsl_esdhc_priv * @@ -103,12 +109,20 @@ struct fsl_esdhc_plat {* @non_removable: 0: removable; 1: non-removable * @wp_enable: 1: enable checking wp; 0: no check * @vs18_enable: 1: use 1.8V voltage; 0: use 3.3V +* @flags: ESDHC_FLAG_xx in include/fsl_esdhc.h +* @caps: controller capabilities +* @tuning_step: tuning step setting in tuning_ctrl register +* @start_tuning_tap: the start point for tuning in tuning_ctrl register +* @strobe_dll_delay_target: settings in strobe_dllctrl +* @signal_voltage: indicating the current voltage * @cd_gpio: gpio for card detection * @wp_gpio: gpio for write protection */ struct fsl_esdhc_priv {struct fsl_esdhc *esdhc_regs;unsigned int sdhc_clk; +unsigned int clock; +unsigned int mode;unsigned int bus_width;#if !CONFIG_IS_ENABLED (BLK )struct mmc *mmc;@@ -117,6 +131,16 @@ struct fsl_esdhc_priv {int non_removable;int wp_enable;int vs18_enable; +u32 flags; +u32 caps; +u32 tuning_step; +u32 tuning_start_tap; +u32 strobe_dll_delay_target; +u32 signal_voltage; +#if IS_ENABLED (CONFIG_DM_REGULATOR ) +struct udevice *vqmmc_dev; +struct udevice *vmmc_dev; +#endif #ifdef CONFIG_DM_GPIO struct gpio_desc cd_gpio;struct gpio_desc wp_gpio;@@ -364,6 +388,7 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc,int err =0 ;uint xfertyp;uint irqstat; +u32 flags;struct fsl_esdhc *regs = priv->esdhc_regs;#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111
drivers/mmc/fsl_esdhc.c static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, · line 450
Quoted 9 lines
drivers/mmc/fsl_esdhc.c +6
-0@@ -417,8 +442,15 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc,esdhc_write32 (®s->xfertyp, xfertyp);#endif +if ((cmd->cmdidx ==MMC_CMD_SEND_TUNING_BLOCK ) || + (cmd->cmdidx ==MMC_CMD_SEND_TUNING_BLOCK_HS200 )) { + flags =IRQSTAT_BRR ; + }else { + flags =IRQSTAT_CC |IRQSTAT_CTOE ; + }
IRQSTAT_CC | IRQSTAT_CTOE can be set to default value like below.
int flags = IRQSTAT_CC | IRQSTAT_CTOE;
Quoted 64 lines
drivers/mmc/fsl_esdhc.c +33
-2+/* Wait for the command to complete */ -while (!(esdhc_read32 (®s->irqstat) & (IRQSTAT_CC |IRQSTAT_CTOE ))) +while (!(esdhc_read32 (®s->irqstat) & flags)) ; irqstat =esdhc_read32 (®s->irqstat);@@ -480,6 +512,12 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO esdhc_pio_read_write(priv, data); #else + flags = DATA_COMPLETE; + if ((cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK) || + (cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200)) { + flags = IRQSTAT_BRR; + } + do { irqstat = esdhc_read32(®s->irqstat);@@ -492,7 +530,7 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, err = -ECOMM ; goto out; } - }while ((irqstat &DATA_COMPLETE ) !=DATA_COMPLETE ); + }while ((irqstat & flags) != flags);/* * Need invalidate the dcache here again to avoid any @@ -573,6 +611,7 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock)esdhc_setbits32 (®s->sysctl,SYSCTL_PEREN |SYSCTL_CKEN );#endif + priv->clock = clock; }#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK @@ -604,9 +643,233 @@ static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) }#endif +#ifdef MMC_SUPPORTS_TUNING +static int esdhc_change_pinstate (struct udevice *dev) +{ +struct fsl_esdhc_priv *priv =dev_get_priv (dev); +int ret; + +switch (priv->mode) { +case UHS_SDR50 : +case UHS_DDR50 : + ret =pinctrl_select_state (dev,"state_100mhz" ); +break ; +case UHS_SDR104 : +case MMC_HS_200 : + ret =pinctrl_select_state (dev,"state_200mhz" ); +break ; +default : + ret =pinctrl_select_state (dev,"default" ); +break ; + } + +if (ret) +printf ("%s %d error\n" , __func__, priv->mode); +
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 678
Quoted 10 lines
drivers/mmc/fsl_esdhc.c +10
-0+return ret; +} + +static void esdhc_reset_tuning (struct mmc *mmc) +{ +struct fsl_esdhc_priv *priv =dev_get_priv (mmc->dev); +struct fsl_esdhc *regs = priv->esdhc_regs; + +if (priv->flags &ESDHC_FLAG_USDHC ) { +if (priv->flags &ESDHC_FLAG_STD_TUNING ) {
Don't need to use "if" condition at here.
if (priv->flags & (ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING) ?
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 690
Quoted 12 lines
drivers/mmc/fsl_esdhc.c +12
-0+esdhc_clrbits32 (®s->autoc12err, +MIX_CTRL_SMPCLK_SEL | +MIX_CTRL_EXE_TUNE ); + } + } +} + +static int esdhc_set_timing (struct mmc *mmc) +{ +struct fsl_esdhc_priv *priv =dev_get_priv (mmc->dev); +struct fsl_esdhc *regs = priv->esdhc_regs; +u32 m;
Ues the meaningful variable name, not just "m".
Quoted 16 lines
drivers/mmc/fsl_esdhc.c +16
-0+ + m =readl (®s->mixctrl); + m &= ~(MIX_CTRL_DDREN |MIX_CTRL_HS400_EN ); + +switch (mmc->selected_mode) { +case MMC_LEGACY : +case SD_LEGACY : +esdhc_reset_tuning (mmc); +break ; +case MMC_HS : +case MMC_HS_52 : +case MMC_HS_200 : +case SD_HS : +case UHS_SDR12 : +case UHS_SDR25 : +case UHS_SDR50 :
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 716
Quoted 10 lines
drivers/mmc/fsl_esdhc.c +10
-0+case UHS_SDR104 : +writel (m, ®s->mixctrl); +break ; +case UHS_DDR50 : +case MMC_DDR_52 : + m |=MIX_CTRL_DDREN ; +writel (m, ®s->mixctrl); +break ; +default : +printf ("Not supported %d\n" , mmc->selected_mode);
Doesn't need to return? Does it need to call esdhc_change_pinstate()?
Quoted 10 lines
drivers/mmc/fsl_esdhc.c +10
-0+break ; + } + + priv->mode = mmc->selected_mode; + +return esdhc_change_pinstate (mmc->dev); +} + +static int esdhc_set_voltage (struct mmc *mmc) +{
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 736
Quoted 10 lines
drivers/mmc/fsl_esdhc.c +10
-0+struct fsl_esdhc_priv *priv =dev_get_priv (mmc->dev); +struct fsl_esdhc *regs = priv->esdhc_regs; +int ret; + + priv->signal_voltage = mmc->signal_voltage; +switch (mmc->signal_voltage) { +case MMC_SIGNAL_VOLTAGE_330 : +if (priv->vs18_enable) +return -EIO ; +if (!IS_ERR_OR_NULL (priv->vqmmc_dev)) {
Not need to check the CONFIG_DM_REGULATOR for vqmmc_dev and vmmc_dev?
Quoted 46 lines
drivers/mmc/fsl_esdhc.c +46
-0+ ret =regulator_set_value (priv->vqmmc_dev,3300000 ); +if (ret) { +printf ("Setting to 3.3V error" ); +return -EIO ; + } +/* Wait for 5ms */ +mdelay (5 ); + } + +esdhc_clrbits32 (®s->vendorspec,ESDHC_VENDORSPEC_VSELECT ); +if (!(esdhc_read32 (®s->vendorspec) & +ESDHC_VENDORSPEC_VSELECT )) +return 0 ; + +return -EAGAIN ; +case MMC_SIGNAL_VOLTAGE_180 : +if (!IS_ERR_OR_NULL (priv->vqmmc_dev)) { + ret =regulator_set_value (priv->vqmmc_dev,1800000 ); +if (ret) { +printf ("Setting to 1.8V error" ); +return -EIO ; + } + } +esdhc_setbits32 (®s->vendorspec,ESDHC_VENDORSPEC_VSELECT ); +if (esdhc_read32 (®s->vendorspec) &ESDHC_VENDORSPEC_VSELECT ) +return 0 ; + +return -EAGAIN ; +case MMC_SIGNAL_VOLTAGE_120 : +return -ENOTSUPP ; +default : +return 0 ; + } +} + +static void esdhc_stop_tuning (struct mmc *mmc) +{ +struct mmc_cmd cmd; + + cmd.cmdidx =MMC_CMD_STOP_TRANSMISSION ; + cmd.cmdarg =0 ; + cmd.resp_type = MMC_RSP_R1b; + +dm_mmc_send_cmd (mmc->dev, &cmd,NULL ); +} +
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 792
Quoted 10 lines
drivers/mmc/fsl_esdhc.c +10
-0+static int fsl_esdhc_execute_tuning (struct udevice *dev,uint32_t opcode) +{ +struct fsl_esdhc_plat *plat =dev_get_platdata (dev); +struct fsl_esdhc_priv *priv =dev_get_priv (dev); +struct fsl_esdhc *regs = priv->esdhc_regs; +struct mmc *mmc = &plat->mmc; +u32 irqstaten =readl (®s->irqstaten); +u32 irqsigen =readl (®s->irqsigen); +int i, ret = -ETIMEDOUT ; +u32 v, m;
Ditto.
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 804
Quoted 12 lines
drivers/mmc/fsl_esdhc.c +12
-0+ +/* clock tuning is not needed for upto 52MHz */ +if (mmc->clock <=52000000 ) +return 0 ; + +/* This is readw/writew SDHCI_HOST_CONTROL2 when tuning */ +if (priv->flags &ESDHC_FLAG_STD_TUNING ) { + v =readl (®s->autoc12err); + m =readl (®s->mixctrl); + v &= ~MIX_CTRL_SMPCLK_SEL ; + m &= ~MIX_CTRL_FBCLK_SEL ; + m &= ~MIX_CTRL_AUTO_TUNE_EN ;
Combine to one line.
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 808
Quoted 4 lines
drivers/mmc/fsl_esdhc.c +4
-0+ + v |=MIX_CTRL_EXE_TUNE ; + m |=MIX_CTRL_FBCLK_SEL ; + m |=MIX_CTRL_AUTO_TUNE_EN ;
Ditto.
Quoted 4 lines
drivers/mmc/fsl_esdhc.c +4
-0+ +writel (v, ®s->autoc12err); +writel (m, ®s->mixctrl); + }
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 822
Quoted 10 lines
drivers/mmc/fsl_esdhc.c +10
-0+ +/* sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); */ + v =readl (®s->mixctrl); + v =MIX_CTRL_DTDSEL_READ | (v & ~MIX_CTRL_SDHCI_MASK ); +writel (v, ®s->mixctrl); + +writel (IRQSTATEN_BRR , ®s->irqstaten); +writel (IRQSTATEN_BRR , ®s->irqsigen); + +for (i =0 ; i <40 ; i++) {
What is 40? don't use the magic number.
Quoted 8 lines
drivers/mmc/fsl_esdhc.c +8
-0+u32 ctrl; + +if (opcode ==MMC_CMD_SEND_TUNING_BLOCK_HS200 ) { +if (mmc->bus_width ==8 ) +writel (0x7080 , ®s->blkattr); +else if (mmc->bus_width ==4 ) +writel (0x7040 , ®s->blkattr); + }else {
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 840
Quoted 10 lines
drivers/mmc/fsl_esdhc.c +10
-0+writel (0x7040 , ®s->blkattr); + } + +/* sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE) */ + v =readl (®s->mixctrl); + v =MIX_CTRL_DTDSEL_READ | (v & ~MIX_CTRL_SDHCI_MASK ); +writel (v, ®s->mixctrl); + +/* We are using STD tuning, no need to check return value */ +mmc_send_tuning (mmc, opcode,NULL );
mmc_send_tuning will have the return value, not need to check?
Quoted 94 lines
drivers/mmc/fsl_esdhc.c +69
-1+ + ctrl =readl (®s->autoc12err); +if ((!(ctrl &MIX_CTRL_EXE_TUNE )) && + (ctrl &MIX_CTRL_SMPCLK_SEL )) { +/* +* need to wait some time, make sure sd/mmc fininsh +* send out tuning data, otherwise, the sd/mmc can't +* response to any command when the card still out +* put the tuning data. +*/ +mdelay (1 ); + ret =0 ; +break ; + } + +/* Add 1ms delay for SD and eMMC */ + mdelay(1); + } + +writel (irqstaten, ®s->irqstaten); +writel (irqsigen, ®s->irqsigen); + +esdhc_stop_tuning (mmc); + +return ret; +} +#endif +static int esdhc_set_ios_common (struct fsl_esdhc_priv *priv,struct mmc *mmc) {struct fsl_esdhc *regs = priv->esdhc_regs; +int ret__maybe_unused ;#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK /* Select to use peripheral clock */ @@ -615,7 +878,41 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)esdhc_clock_control (priv, true);#endif /* Set the clock speed */ -set_sysctl (priv, mmc, mmc->clock); +if (priv->clock != mmc->clock) +set_sysctl (priv, mmc, mmc->clock); + +#ifdef MMC_SUPPORTS_TUNING +if (mmc->clk_disable) { +#ifdef CONFIG_FSL_USDHC +esdhc_clrbits32 (®s->vendorspec,VENDORSPEC_CKEN ); +#else +esdhc_clrbits32 (®s->sysctl,SYSCTL_CKEN ); +#endif + }else { +#ifdef CONFIG_FSL_USDHC +esdhc_setbits32 (®s->vendorspec,VENDORSPEC_PEREN | +VENDORSPEC_CKEN ); +#else +esdhc_setbits32 (®s->sysctl,SYSCTL_PEREN |SYSCTL_CKEN ); +#endif + } + +if (priv->mode != mmc->selected_mode) { + ret =esdhc_set_timing (mmc); +if (ret) { +printf ("esdhc_set_timing error %d\n" , ret); +return ret; + } + } + +if (priv->signal_voltage != mmc->signal_voltage) { + ret =esdhc_set_voltage (mmc); +if (ret) { +printf ("esdhc_set_voltage error %d\n" , ret); +return ret; + } + } +#endif /* Set the bus width */ esdhc_clrbits32 (®s->proctl,PROCTL_DTW_4 |PROCTL_DTW_8 );@@ -790,6 +1087,10 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv,#ifndef CONFIG_FSL_USDHC esdhc_setbits32 (®s->sysctl,SYSCTL_PEREN |SYSCTL_HCKEN |SYSCTL_IPGEN |SYSCTL_CKEN ); +/* Clearing tuning bits in case ROM has set it already */ +esdhc_write32 (®s->mixctrl,0 ); +esdhc_write32 (®s->autoc12err,0 ); +esdhc_write32 (®s->clktunectrlstatus,0 );#else esdhc_setbits32 (®s->vendorspec,VENDORSPEC_PEREN |VENDORSPEC_HCKEN |VENDORSPEC_IPGEN |VENDORSPEC_CKEN );@@ -863,11 +1164,27 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv, cfg->host_caps &= ~MMC_MODE_8BIT ;#endif + cfg->host_caps |= priv->caps;
drivers/mmc/fsl_esdhc.c static int fsl_esdhc_init(struct fsl_esdhc_priv *priv, · line 1176
Quoted 10 lines
drivers/mmc/fsl_esdhc.c +5
-1+ cfg->f_min =400000 ; - cfg->f_max =min (priv->sdhc_clk, (u32 )52000000 ); + cfg->f_max =min (priv->sdhc_clk, (u32 )200000000 ); cfg->b_max =CONFIG_SYS_MMC_MAX_BLK_COUNT ; +writel (0 , ®s->dllctrl); +if (priv->flags &ESDHC_FLAG_USDHC ) { +if (priv->flags &ESDHC_FLAG_STD_TUNING ) {
Ditto.
Quoted 157 lines
drivers/mmc/fsl_esdhc.c +44
-1+u32 val =readl (®s->tuning_ctrl); + + val |=ESDHC_STD_TUNING_EN ; + val &= ~ESDHC_TUNING_START_TAP_MASK ; + val |= priv->tuning_start_tap; + val &= ~ESDHC_TUNING_STEP_MASK ; + val |= (priv->tuning_step) <<ESDHC_TUNING_STEP_SHIFT ; +writel (val, ®s->tuning_ctrl); + } + } +return 0 ; }@@ -1026,6 +1343,10 @@ static int fsl_esdhc_probe(struct udevice *dev)struct mmc_uclass_priv *upriv =dev_get_uclass_priv (dev);struct fsl_esdhc_plat *plat =dev_get_platdata (dev);struct fsl_esdhc_priv *priv =dev_get_priv (dev); +const void *fdt = gd->fdt_blob; +int node =dev_of_offset (dev); +struct esdhc_soc_data *data = + (struct esdhc_soc_data *)dev_get_driver_data (dev);#ifdef CONFIG_DM_REGULATOR struct udevice *vqmmc_dev;#endif @@ -1040,6 +1361,11 @@ static int fsl_esdhc_probe(struct udevice *dev) priv->esdhc_regs = (struct fsl_esdhc *)addr; priv->dev = dev; + priv->mode =-1 ; +if (data) { + priv->flags = data->flags; + priv->caps = data->caps; + } val =dev_read_u32_default (dev,"bus-width" ,-1 );if (val ==8 )@@ -1049,6 +1375,15 @@ static int fsl_esdhc_probe(struct udevice *dev)else priv->bus_width =1 ; + val =fdtdec_get_int (fdt, node,"fsl,tuning-step" ,1 ); + priv->tuning_step = val; + val =fdtdec_get_int (fdt, node,"fsl,tuning-start-tap" , +ESDHC_TUNING_START_TAP_DEFAULT ); + priv->tuning_start_tap = val; + val =fdtdec_get_int (fdt, node,"fsl,strobe-dll-delay-target" , +ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT ); + priv->strobe_dll_delay_target = val; +if (dev_read_bool (dev,"non-removable" )) { priv->non_removable =1 ; }else {@@ -1090,6 +1425,9 @@ static int fsl_esdhc_probe(struct udevice *dev) }#endif +if (fdt_get_property (fdt, node,"no-1-8-v" ,NULL )) + priv->caps &= ~(UHS_CAPS |MMC_MODE_HS200 ); +/* * TODO: * Because lack of clk driver, if SDHC clk is not enabled, @@ -1162,15 +1500,26 @@ static const struct dm_mmc_ops fsl_esdhc_ops = { .get_cd = fsl_esdhc_get_cd, .send_cmd = fsl_esdhc_send_cmd, .set_ios = fsl_esdhc_set_ios, +#ifdef MMC_SUPPORTS_TUNING + .execute_tuning = fsl_esdhc_execute_tuning, +#endif };#endif +static struct esdhc_soc_data usdhc_imx7d_data = { + .flags =ESDHC_FLAG_USDHC |ESDHC_FLAG_STD_TUNING + |ESDHC_FLAG_HAVE_CAP1 |ESDHC_FLAG_HS200 + |ESDHC_FLAG_HS400 , + .caps =UHS_CAPS |MMC_MODE_HS200 | MMC_MODE_DDR_52MHz | + MMC_MODE_HS_52MHz |MMC_MODE_HS , +}; +static const struct udevice_id fsl_esdhc_ids[] = { { .compatible ="fsl,imx6ul-usdhc" , }, { .compatible ="fsl,imx6sx-usdhc" , }, { .compatible ="fsl,imx6sl-usdhc" , }, { .compatible ="fsl,imx6q-usdhc" , }, - { .compatible ="fsl,imx7d-usdhc" , }, + { .compatible ="fsl,imx7d-usdhc" , .data = (ulong)&usdhc_imx7d_data,}, { .compatible ="fsl,imx7ulp-usdhc" , }, { .compatible ="fsl,esdhc" , }, {/* sentinel */ }include/fsl_esdhc.h +47
-0@@ -10,6 +10,7 @@#ifndef __FSL_ESDHC_H__#define __FSL_ESDHC_H__ +#include <linux/bitops.h> #include <linux/errno.h> #include <asm/byteorder.h> @@ -173,6 +174,52 @@#define ESDHC_VENDORSPEC_VSELECT 0x00000002/* Use 1.8V */ +/* Imported from Linux Kernel drivers/mmc/host/sdhci-esdhc-imx.c */ +#define MIX_CTRL_DDREN BIT(3) +#define MIX_CTRL_DTDSEL_READ BIT(4) +#define MIX_CTRL_AC23EN BIT(7) +#define MIX_CTRL_EXE_TUNE BIT(22) +#define MIX_CTRL_SMPCLK_SEL BIT(23) +#define MIX_CTRL_AUTO_TUNE_EN BIT(24) +#define MIX_CTRL_FBCLK_SEL BIT(25) +#define MIX_CTRL_HS400_EN BIT(26) +#define MIX_CTRL_HS400_ES BIT(27) +/* Bits 3 and 6 are not SDHCI standard definitions */ +#define MIX_CTRL_SDHCI_MASK 0xb7 +/* Tuning bits */ +#define MIX_CTRL_TUNING_MASK 0x03c00000 + +/* strobe dll register */ +#define ESDHC_STROBE_DLL_CTRL 0x70 +#define ESDHC_STROBE_DLL_CTRL_ENABLE BIT(0) +#define ESDHC_STROBE_DLL_CTRL_RESET BIT(1) +#define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT 0x7 +#define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT 3 + +#define ESDHC_STROBE_DLL_STATUS 0x74 +#define ESDHC_STROBE_DLL_STS_REF_LOCK BIT(1) +#define ESDHC_STROBE_DLL_STS_SLV_LOCK 0x1 +#define ESDHC_STROBE_DLL_CLK_FREQ 100000000 + +#define ESDHC_STD_TUNING_EN BIT(24) +/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ +#define ESDHC_TUNING_START_TAP_DEFAULT 0x1 +#define ESDHC_TUNING_START_TAP_MASK 0xff +#define ESDHC_TUNING_STEP_MASK 0x00070000 +#define ESDHC_TUNING_STEP_SHIFT 16 + +#define ESDHC_FLAG_MULTIBLK_NO_INT BIT(1) +#define ESDHC_FLAG_ENGCM07207 BIT(2) +#define ESDHC_FLAG_USDHC BIT(3) +#define ESDHC_FLAG_MAN_TUNING BIT(4) +#define ESDHC_FLAG_STD_TUNING BIT(5) +#define ESDHC_FLAG_HAVE_CAP1 BIT(6) +#define ESDHC_FLAG_ERR004536 BIT(7) +#define ESDHC_FLAG_HS200 BIT(8) +#define ESDHC_FLAG_HS400 BIT(9) +#define ESDHC_FLAG_ERR010450 BIT(10) +#define ESDHC_FLAG_HS400_ES BIT(11) +struct fsl_esdhc_cfg {phys_addr_t esdhc_base;u32 sdhc_clk;
PATCH 4/5 mmc: fsl_esdhc: support SDR104 and HS200
Quoted 177 lines · Jaehoon Chung
Quoted 93 lines · Peng Fan
Introduce SDR104 and HS200 support
The implementation takes linux kernelsdhci.candsdhci-esdhc-imx.cas reference.
- Implementesdhc_change_pinstateto dynamically change pad settings
- Implementesdhc_set_timing
- Implementesdhc_set_voltageto switch voltage
- Implementfsl_esdhc_execute_tuningto execute time process
- Enlarge thecfg->f_maxto 200MHz.
- Parse fsl,tuning-step, fsl,tuning-start-tap and fsl,strobe-dll-delay-target from device tree.
- Parse no-1-8-v property
- Introduceesdhc_soc_datato indicate the flags and capsSigned-off-by Peng Fan <[email protected]>Cc Stefano Babic <[email protected]>Cc Fabio Estevam <[email protected]>Cc Jaehoon Chung <[email protected]>--- drivers/mmc/fsl_esdhc.c | 359 +++++++++++++++++++++++++++++++++++++++++++++++- include/fsl_esdhc.h | 47 +++++++ 2 files changed, 401 insertions(+), 5 deletions(-)drivers/mmc/fsl_esdhc.c +25
-0@@ -23,6 +23,7 @@#include <asm/io.h> #include <dm.h> #include <asm-generic/gpio.h> +#include <dm/pinctrl.h> DECLARE_GLOBAL_DATA_PTR ;@@ -90,6 +91,11 @@ struct fsl_esdhc_plat {struct mmc mmc; }; +struct esdhc_soc_data { +u32 flags; +u32 caps; +}; +/** * struct fsl_esdhc_priv * @@ -103,12 +109,20 @@ struct fsl_esdhc_plat {* @non_removable: 0: removable; 1: non-removable * @wp_enable: 1: enable checking wp; 0: no check * @vs18_enable: 1: use 1.8V voltage; 0: use 3.3V +* @flags: ESDHC_FLAG_xx in include/fsl_esdhc.h +* @caps: controller capabilities +* @tuning_step: tuning step setting in tuning_ctrl register +* @start_tuning_tap: the start point for tuning in tuning_ctrl register +* @strobe_dll_delay_target: settings in strobe_dllctrl +* @signal_voltage: indicating the current voltage * @cd_gpio: gpio for card detection * @wp_gpio: gpio for write protection */ struct fsl_esdhc_priv {struct fsl_esdhc *esdhc_regs;unsigned int sdhc_clk; +unsigned int clock; +unsigned int mode;unsigned int bus_width;#if !CONFIG_IS_ENABLED (BLK )struct mmc *mmc;@@ -117,6 +131,16 @@ struct fsl_esdhc_priv {int non_removable;int wp_enable;int vs18_enable; +u32 flags; +u32 caps; +u32 tuning_step; +u32 tuning_start_tap; +u32 strobe_dll_delay_target; +u32 signal_voltage; +#if IS_ENABLED (CONFIG_DM_REGULATOR ) +struct udevice *vqmmc_dev; +struct udevice *vmmc_dev; +#endif #ifdef CONFIG_DM_GPIO struct gpio_desc cd_gpio;struct gpio_desc wp_gpio;@@ -364,6 +388,7 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc,int err =0 ;uint xfertyp;uint irqstat; +u32 flags;struct fsl_esdhc *regs = priv->esdhc_regs;#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 drivers/mmc/fsl_esdhc.c static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, · line 450
Quoted 9 lines
drivers/mmc/fsl_esdhc.c +6
-0@@ -417,8 +442,15 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc,esdhc_write32 (®s->xfertyp, xfertyp);#endif +if ((cmd->cmdidx ==MMC_CMD_SEND_TUNING_BLOCK ) || + (cmd->cmdidx ==MMC_CMD_SEND_TUNING_BLOCK_HS200 )) { + flags =IRQSTAT_BRR ; + }else { + flags =IRQSTAT_CC |IRQSTAT_CTOE ; + }
IRQSTAT_CC|IRQSTAT_CTOEcan be set to default value like below.int flags =
IRQSTAT_CC|IRQSTAT_CTOE;Quoted 69 lines
drivers/mmc/fsl_esdhc.c +38
-2+/* Wait for the command to complete */ -while (!(esdhc_read32 (®s->irqstat) & (IRQSTAT_CC |IRQSTAT_CTOE ))) +while (!(esdhc_read32 (®s->irqstat) & flags)) ; irqstat =esdhc_read32 (®s->irqstat);@@ -480,6 +512,12 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO esdhc_pio_read_write(priv, data); #else + flags = DATA_COMPLETE; + if ((cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK) || + (cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200)) { + flags = IRQSTAT_BRR; + } + do { irqstat = esdhc_read32(®s->irqstat);@@ -492,7 +530,7 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, err = -ECOMM ; goto out; } - }while ((irqstat &DATA_COMPLETE ) !=DATA_COMPLETE ); + }while ((irqstat & flags) != flags);/* * Need invalidate the dcache here again to avoid any @@ -573,6 +611,7 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock)esdhc_setbits32 (®s->sysctl,SYSCTL_PEREN |SYSCTL_CKEN );#endif + priv->clock = clock; }#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK @@ -604,9 +643,233 @@ static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) }#endif +#ifdef MMC_SUPPORTS_TUNING +static int esdhc_change_pinstate (struct udevice *dev) +{ +struct fsl_esdhc_priv *priv =dev_get_priv (dev); +int ret; + +switch (priv->mode) { +case UHS_SDR50 : +case UHS_DDR50 : + ret =pinctrl_select_state (dev,"state_100mhz" ); +break ; +case UHS_SDR104 : +case MMC_HS_200 : + ret =pinctrl_select_state (dev,"state_200mhz" ); +break ; +default : + ret =pinctrl_select_state (dev,"default" ); +break ; + } + +if (ret) +printf ("%s %d error\n" , __func__, priv->mode); + +return ret; +} + +static void esdhc_reset_tuning (struct mmc *mmc) +{
Quoted 8 lines
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 678
Quoted 5 lines
drivers/mmc/fsl_esdhc.c +5
-0+struct fsl_esdhc_priv *priv =dev_get_priv (mmc->dev); +struct fsl_esdhc *regs = priv->esdhc_regs; + +if (priv->flags &ESDHC_FLAG_USDHC ) { +if (priv->flags &ESDHC_FLAG_STD_TUNING ) {Don't need to use "if" condition at here.
if (priv->flags& (ESDHC_FLAG_USDHC|ESDHC_FLAG_STD_TUNING) ?
This is another condition is to check ESDHC_FLAG_MAN_TUNING. In this patch I did not add that support.
So let's keep as it is for later add MAN tuning.
Quoted 15 lines
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 690
Quoted 13 lines
drivers/mmc/fsl_esdhc.c +12
-0+esdhc_clrbits32 (®s->autoc12err, +MIX_CTRL_SMPCLK_SEL | +MIX_CTRL_EXE_TUNE ); + } + } +} + +static int esdhc_set_timing (struct mmc *mmc) +{ +struct fsl_esdhc_priv *priv =dev_get_priv (mmc->dev); +struct fsl_esdhc *regs = priv->esdhc_regs; +u32 m;Ues the meaningful variable name, not just "m".
use mixctrl in v2.
Quoted 21 lines
Quoted 21 lines
drivers/mmc/fsl_esdhc.c +20
-0+ + m =readl (®s->mixctrl); + m &= ~(MIX_CTRL_DDREN |MIX_CTRL_HS400_EN ); + +switch (mmc->selected_mode) { +case MMC_LEGACY : +case SD_LEGACY : +esdhc_reset_tuning (mmc); +break ; +case MMC_HS : +case MMC_HS_52 : +case MMC_HS_200 : +case SD_HS : +case UHS_SDR12 : +case UHS_SDR25 : +case UHS_SDR50 : +case UHS_SDR104 : +writel (m, ®s->mixctrl); +break ; +case UHS_DDR50 :
Quoted 8 lines
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 716
Quoted 6 lines
drivers/mmc/fsl_esdhc.c +6
-0+case MMC_DDR_52 : + m |=MIX_CTRL_DDREN ; +writel (m, ®s->mixctrl); +break ; +default : +printf ("Not supported %d\n" , mmc->selected_mode);Doesn't need to return? Does it need to call
esdhc_change_pinstate()?
need return here. Fix in V2.
Quoted 15 lines
Quoted 15 lines
drivers/mmc/fsl_esdhc.c +14
-0+break ; + } + + priv->mode = mmc->selected_mode; + +return esdhc_change_pinstate (mmc->dev); +} + +static int esdhc_set_voltage (struct mmc *mmc) +{ +struct fsl_esdhc_priv *priv =dev_get_priv (mmc->dev); +struct fsl_esdhc *regs = priv->esdhc_regs; +int ret; +
Quoted 8 lines
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 736
Quoted 6 lines
drivers/mmc/fsl_esdhc.c +6
-0+ priv->signal_voltage = mmc->signal_voltage; +switch (mmc->signal_voltage) { +case MMC_SIGNAL_VOLTAGE_330 : +if (priv->vs18_enable) +return -EIO ; +if (!IS_ERR_OR_NULL (priv->vqmmc_dev)) {Not need to check the
CONFIG_DM_REGULATORforvqmmc_devandvmmc_dev?
The support for UHS or HS200 assumes DM_REGULATOR enabled. If no regulator support, the UHS or HS200 will not work.
Quoted 51 lines
Quoted 51 lines
drivers/mmc/fsl_esdhc.c +50
-0+ ret =regulator_set_value (priv->vqmmc_dev,3300000 ); +if (ret) { +printf ("Setting to 3.3V error" ); +return -EIO ; + } +/* Wait for 5ms */ +mdelay (5 ); + } + +esdhc_clrbits32 (®s->vendorspec,ESDHC_VENDORSPEC_VSELECT ); +if (!(esdhc_read32 (®s->vendorspec) & +ESDHC_VENDORSPEC_VSELECT )) +return 0 ; + +return -EAGAIN ; +case MMC_SIGNAL_VOLTAGE_180 : +if (!IS_ERR_OR_NULL (priv->vqmmc_dev)) { + ret =regulator_set_value (priv->vqmmc_dev,1800000 ); +if (ret) { +printf ("Setting to 1.8V error" ); +return -EIO ; + } + } +esdhc_setbits32 (®s->vendorspec,ESDHC_VENDORSPEC_VSELECT ); +if (esdhc_read32 (®s->vendorspec) &ESDHC_VENDORSPEC_VSELECT ) +return 0 ; + +return -EAGAIN ; +case MMC_SIGNAL_VOLTAGE_120 : +return -ENOTSUPP ; +default : +return 0 ; + } +} + +static void esdhc_stop_tuning (struct mmc *mmc) +{ +struct mmc_cmd cmd; + + cmd.cmdidx =MMC_CMD_STOP_TRANSMISSION ; + cmd.cmdarg =0 ; + cmd.resp_type = MMC_RSP_R1b; + +dm_mmc_send_cmd (mmc->dev, &cmd,NULL ); +} + +static int fsl_esdhc_execute_tuning (struct udevice *dev,uint32_t opcode) +{ +struct fsl_esdhc_plat *plat =dev_get_platdata (dev); +struct fsl_esdhc_priv *priv =dev_get_priv (dev);
Quoted 8 lines
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 792
Quoted 6 lines
drivers/mmc/fsl_esdhc.c +6
-0+struct fsl_esdhc *regs = priv->esdhc_regs; +struct mmc *mmc = &plat->mmc; +u32 irqstaten =readl (®s->irqstaten); +u32 irqsigen =readl (®s->irqsigen); +int i, ret = -ETIMEDOUT ; +u32 v, m;Ditto.
fix in V2.
Quoted 15 lines
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 804
Quoted 13 lines
drivers/mmc/fsl_esdhc.c +12
-0+ +/* clock tuning is not needed for upto 52MHz */ +if (mmc->clock <=52000000 ) +return 0 ; + +/* This is readw/writew SDHCI_HOST_CONTROL2 when tuning */ +if (priv->flags &ESDHC_FLAG_STD_TUNING ) { + v =readl (®s->autoc12err); + m =readl (®s->mixctrl); + v &= ~MIX_CTRL_SMPCLK_SEL ; + m &= ~MIX_CTRL_FBCLK_SEL ; + m &= ~MIX_CTRL_AUTO_TUNE_EN ;Combine to one line.
Fix in V2.
Quoted 7 lines
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 808
Quoted 5 lines
drivers/mmc/fsl_esdhc.c +4
-0+ + v |=MIX_CTRL_EXE_TUNE ; + m |=MIX_CTRL_FBCLK_SEL ; + m |=MIX_CTRL_AUTO_TUNE_EN ;Ditto.
Fix in V2.
Quoted 17 lines
Quoted 5 lines
drivers/mmc/fsl_esdhc.c +4
-0+ +writel (v, ®s->autoc12err); +writel (m, ®s->mixctrl); + }drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 822
Quoted 10 lines
drivers/mmc/fsl_esdhc.c +10
-0+ +/* sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); */ + v =readl (®s->mixctrl); + v =MIX_CTRL_DTDSEL_READ | (v & ~MIX_CTRL_SDHCI_MASK ); +writel (v, ®s->mixctrl); + +writel (IRQSTATEN_BRR , ®s->irqstaten); +writel (IRQSTATEN_BRR , ®s->irqsigen); + +for (i =0 ; i <40 ; i++) {What is 40? don't use the magic number.
Fix in V2.
Quoted 13 lines
Quoted 13 lines
drivers/mmc/fsl_esdhc.c +12
-0+u32 ctrl; + +if (opcode ==MMC_CMD_SEND_TUNING_BLOCK_HS200 ) { +if (mmc->bus_width ==8 ) +writel (0x7080 , ®s->blkattr); +else if (mmc->bus_width ==4 ) +writel (0x7040 , ®s->blkattr); + }else { +writel (0x7040 , ®s->blkattr); + } + +/* sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE) */
Quoted 8 lines
drivers/mmc/fsl_esdhc.c static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) · line 840
Quoted 6 lines
drivers/mmc/fsl_esdhc.c +6
-0+ v =readl (®s->mixctrl); + v =MIX_CTRL_DTDSEL_READ | (v & ~MIX_CTRL_SDHCI_MASK ); +writel (v, ®s->mixctrl); + +/* We are using STD tuning, no need to check return value */ +mmc_send_tuning (mmc, opcode,NULL );
mmc_send_tuningwill have the return value, not need to check?
You could see the following code, checking EXE_TUNE and SMPCLK_SEL. The two bits are indicating tuning sucess or failure.
Quoted 100 lines
Quoted 100 lines
drivers/mmc/fsl_esdhc.c +71
-2+ + ctrl =readl (®s->autoc12err); +if ((!(ctrl &MIX_CTRL_EXE_TUNE )) && + (ctrl &MIX_CTRL_SMPCLK_SEL )) { +/* +* need to wait some time, make sure sd/mmc fininsh +* send out tuning data, otherwise, the sd/mmc can't +* response to any command when the card still out +* put the tuning data. +*/ +mdelay (1 ); + ret =0 ; +break ; + } + +/* Add 1ms delay for SD and eMMC */ + mdelay(1); + } + +writel (irqstaten, ®s->irqstaten); +writel (irqsigen, ®s->irqsigen); + +esdhc_stop_tuning (mmc); + +return ret; +} +#endif +static int esdhc_set_ios_common (struct fsl_esdhc_priv *priv,struct mmc *mmc) {struct fsl_esdhc *regs = priv->esdhc_regs; +int ret__maybe_unused ;#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK /* Select to use peripheral clock */ @@ -615,7 +878,41 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)esdhc_clock_control (priv, true);#endif /* Set the clock speed */ -set_sysctl (priv, mmc, mmc->clock); +if (priv->clock != mmc->clock) +set_sysctl (priv, mmc, mmc->clock); + +#ifdef MMC_SUPPORTS_TUNING +if (mmc->clk_disable) { +#ifdef CONFIG_FSL_USDHC +esdhc_clrbits32 (®s->vendorspec,VENDORSPEC_CKEN ); +#else +esdhc_clrbits32 (®s->sysctl,SYSCTL_CKEN ); +#endif + }else { +#ifdef CONFIG_FSL_USDHC +esdhc_setbits32 (®s->vendorspec,VENDORSPEC_PEREN | +VENDORSPEC_CKEN ); +#else +esdhc_setbits32 (®s->sysctl,SYSCTL_PEREN |SYSCTL_CKEN ); +#endif + } + +if (priv->mode != mmc->selected_mode) { + ret =esdhc_set_timing (mmc); +if (ret) { +printf ("esdhc_set_timing error %d\n" , ret); +return ret; + } + } + +if (priv->signal_voltage != mmc->signal_voltage) { + ret =esdhc_set_voltage (mmc); +if (ret) { +printf ("esdhc_set_voltage error %d\n" , ret); +return ret; + } + } +#endif /* Set the bus width */ esdhc_clrbits32 (®s->proctl,PROCTL_DTW_4 |PROCTL_DTW_8 );@@ -790,6 +1087,10 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv,#ifndef CONFIG_FSL_USDHC esdhc_setbits32 (®s->sysctl,SYSCTL_PEREN |SYSCTL_HCKEN |SYSCTL_IPGEN |SYSCTL_CKEN ); +/* Clearing tuning bits in case ROM has set it already */ +esdhc_write32 (®s->mixctrl,0 ); +esdhc_write32 (®s->autoc12err,0 ); +esdhc_write32 (®s->clktunectrlstatus,0 );#else esdhc_setbits32 (®s->vendorspec,VENDORSPEC_PEREN |VENDORSPEC_HCKEN |VENDORSPEC_IPGEN |VENDORSPEC_CKEN );@@ -863,11 +1164,27 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv, cfg->host_caps &= ~MMC_MODE_8BIT ;#endif + cfg->host_caps |= priv->caps; + cfg->f_min =400000 ; - cfg->f_max =min (priv->sdhc_clk, (u32 )52000000 ); + cfg->f_max =min (priv->sdhc_clk, (u32 )200000000 );
Quoted 7 lines
drivers/mmc/fsl_esdhc.c static int fsl_esdhc_init(struct fsl_esdhc_priv *priv, · line 1176
Quoted 5 lines
drivers/mmc/fsl_esdhc.c +3
-0cfg->b_max =CONFIG_SYS_MMC_MAX_BLK_COUNT ; +writel (0 , ®s->dllctrl); +if (priv->flags &ESDHC_FLAG_USDHC ) { +if (priv->flags &ESDHC_FLAG_STD_TUNING ) {Ditto.
This is for later to introduce MAN tuning, need add an new checking..
THanks,
Peng
PATCH 5/5 imx: mx7dsabresd: enable UHS and HS200
In reply to Peng FanEnable UHS and HS200 for mx7dsabresd.
Read Speed improvement:
Kingston SD10VG2/16GB SDHC 3.0 card 22.2MB/s -> 73.7MB/s
eMMC5.0 MTFC8GACAEAM:
68MB/s -> 87MB/s
--- configs/mx7dsabresd_defconfig | 3 +++ configs/mx7dsabresd_secure_defconfig | 3 +++ 2 files changed, 6 insertions(+)
configs/mx7dsabresd_defconfig +3 -0
@@ -41,6 +41,9 @@ CONFIG_DM_GPIO=y CONFIG_DM_74X164=y CONFIG_DM_I2C=y CONFIG_DM_MMC=y +CONFIG_MMC_IO_VOLTAGE=y +CONFIG_MMC_UHS_SUPPORT=y +CONFIG_MMC_HS200_SUPPORT=y CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_EON=y CONFIG_PHYLIB=y
configs/mx7dsabresd_secure_defconfig +3 -0
@@ -43,6 +43,9 @@ CONFIG_DM_GPIO=y CONFIG_DM_74X164=y CONFIG_DM_I2C=y CONFIG_DM_MMC=y +CONFIG_MMC_IO_VOLTAGE=y +CONFIG_MMC_UHS_SUPPORT=y +CONFIG_MMC_HS200_SUPPORT=y CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_EON=y CONFIG_PHYLIB=y
Signature · 1 line
2.14.1
Fabio Estevam
reviewerPATCH 1/5 imx: mx7: change sdhc clk to 392M
In reply to Peng FanHi Peng,
Quoted 1 line · Peng Fan
Change sdhc clk to 392M.
392 MHz here and in the Subject, please.
Quoted 15 lines
Prepare support for SDR104 and HS200.
Signed-off-by Peng Fan <[email protected]>Cc Stefano Babic <[email protected]>Cc Fabio Estevam <[email protected]>Cc Jaehoon Chung <[email protected]>--- arch/arm/mach-imx/mx7/clock.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)arch/arm/mach-imx/mx7/clock.c +0
-0
arch/arm/mach-imx/mx7/clock.c static void init_clk_esdhc(void) · line 561
Quoted 1 line
arch/arm/mach-imx/mx7/clock.c +0
-0@@ -561,17 +561,17 @@ static void init_clk_esdhc(void)/* 196: 392/2 */
Please remove this line of comment as it is no longer true after this patch.
PATCH 1/5 imx: mx7: change sdhc clk to 392M
Hi Fabio
Quoted 8 lines
-----Original Message-----
From: Fabio Estevam [mailto:festevam at gmail.com]
Sent: Sunday, January 21, 2018 4:07 AM
To: Peng Fan <[email protected]>
Cc: Stefano Babic <[email protected]>; U-Boot-Denx <[email protected]>; Fabio Estevam <[email protected]>
Subject: Re: [U-Boot] [PATCH 1/5] imx: mx7: change sdhc clk to 392M
Quoted 6 lines
Hi Peng,
Quoted 1 line · Peng Fan
Change sdhc clk to 392M.
392 MHz here and in the Subject, please.
Thanks for comments. In V2, I think this patch could be droped. 196MHz is enough here.
Thanks,
Peng.
Quoted 19 lines
Quoted 16 lines
Prepare support for SDR104 and HS200.
Signed-off-by Peng Fan <[email protected]>Cc Stefano Babic <[email protected]>Cc Fabio Estevam <[email protected]>Cc Jaehoon Chung <[email protected]>--- arch/arm/mach-imx/mx7/clock.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)(quoted diff) +0
-0
b/arch/arm/mach-imx/mx7/clock.cindexc11042d6f5..227037c53d100644arch/arm/mach-imx/mx7/clock.c static void init_clk_esdhc(void) · line 561
Quoted 1 line
arch/arm/mach-imx/mx7/clock.c +0
-0@@ -561,17 +561,17 @@ static void init_clk_esdhc(void)/* 196: 392/2 */ Please remove this line of comment as it is no longer true after this patch.