Message ID | 1382093661-4074-2-git-send-email-b29396@freescale.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Fri, Oct 18, 2013 at 07:33:50PM +0800, Shawn Guo wrote: > On Fri, Oct 18, 2013 at 06:54:14PM +0800, Dong Aisheng wrote: > > The mx6sl supports standard sdhci tuning, then esdhc_executing_tuning > > is only needed for mx6q/dl. We introduce is_imx6_usdhc() and > > is_imx6sl_usdhc() to handle the difference. > > > > The standard tuning is enabled by setting ESDHC_TUNE_CTRL_STD_TUNING_EN bit > > in new register ESDHC_TUNE_CTRL and operates with new tuning bits > > defined in SDHCI_ACMD12_ERR register. > > > > Note: mx6sl can also work on the old manually tuning mode as mx6q/dl if > > not enable standard tuning mode. > > > > Signed-off-by: Dong Aisheng <b29396@freescale.com> > > --- > > drivers/mmc/host/sdhci-esdhc-imx.c | 90 +++++++++++++++++++++++++++++------- > > 1 files changed, 73 insertions(+), 17 deletions(-) > > > > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c > > index c84c808..a4e0e3b 100644 > > --- a/drivers/mmc/host/sdhci-esdhc-imx.c > > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c > > @@ -51,6 +51,11 @@ > > #define ESDHC_TUNE_CTRL_MIN 0 > > #define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1) > > > > +#define ESDHC_TUNING_CTRL 0xcc > > +#define ESDHC_STD_TUNING_EN (1 << 24) > > +/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ > > +#define ESDHC_TUNING_START_TAP 0x1 > > + > > #define ESDHC_TUNING_BLOCK_PATTERN_LEN 64 > > > > /* pinctrl state */ > > @@ -94,6 +99,12 @@ > > * integrated on the i.MX6 series. > > */ > > #define ESDHC_FLAG_USDHC BIT(3) > > +/* The IP supports manual tuning process */ > > +#define ESDHC_FLAG_MAN_TUNING BIT(4) > > +/* The IP supports standard tuning process */ > > +#define ESDHC_FLAG_STD_TUNING BIT(4) > > BIT(4) for both flags? > Oh no, it's copy&paste error. My mistake. Will update it. Regards Dong Aisheng > Shawn > > > +/* The IP has SDHCI_CAPABILITIES_1 register */ > > +#define ESDHC_FLAG_HAVE_CAP1 BIT(5) > > > > struct esdhc_soc_data { > > u32 flags; > > @@ -116,7 +127,12 @@ static struct esdhc_soc_data esdhc_imx53_data = { > > }; > > > > static struct esdhc_soc_data usdhc_imx6q_data = { > > - .flags = ESDHC_FLAG_USDHC, > > + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING, > > +}; > > + > > +static struct esdhc_soc_data usdhc_imx6sl_data = { > > + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING > > + | ESDHC_FLAG_HAVE_CAP1, > > }; > > > > struct pltfm_imx_data { > > @@ -159,6 +175,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { > > { .compatible = "fsl,imx35-esdhc", .data = &esdhc_imx35_data, }, > > { .compatible = "fsl,imx51-esdhc", .data = &esdhc_imx51_data, }, > > { .compatible = "fsl,imx53-esdhc", .data = &esdhc_imx53_data, }, > > + { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, }, > > { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, }, > > { /* sentinel */ } > > }; > > @@ -222,9 +239,16 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) > > } > > } > > > > - if (unlikely(reg == SDHCI_CAPABILITIES_1) && esdhc_is_usdhc(imx_data)) > > - val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 > > - | SDHCI_SUPPORT_SDR50; > > + if (unlikely(reg == SDHCI_CAPABILITIES_1)) { > > + if (esdhc_is_usdhc(imx_data)) { > > + if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1) > > + val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF; > > + else > > + /* imx6q/dl does not have cap_1 register, fake one */ > > + val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 > > + | SDHCI_SUPPORT_SDR50; > > + } > > + } > > > > if (unlikely(reg == SDHCI_MAX_CURRENT) && esdhc_is_usdhc(imx_data)) { > > val = 0; > > @@ -331,13 +355,18 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg) > > ret |= SDHCI_CTRL_VDD_180; > > > > if (esdhc_is_usdhc(imx_data)) { > > - val = readl(host->ioaddr + ESDHC_MIX_CTRL); > > - if (val & ESDHC_MIX_CTRL_EXE_TUNE) > > - ret |= SDHCI_CTRL_EXEC_TUNING; > > - if (val & ESDHC_MIX_CTRL_SMPCLK_SEL) > > - ret |= SDHCI_CTRL_TUNED_CLK; > > + if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) > > + val = readl(host->ioaddr + ESDHC_MIX_CTRL); > > + else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) > > + /* the std tuning bits is in ACMD12_ERR for imx6sl */ > > + val = readl(host->ioaddr + SDHCI_ACMD12_ERR); > > } > > > > + if (val & ESDHC_MIX_CTRL_EXE_TUNE) > > + ret |= SDHCI_CTRL_EXEC_TUNING; > > + if (val & ESDHC_MIX_CTRL_SMPCLK_SEL) > > + ret |= SDHCI_CTRL_TUNED_CLK; > > + > > ret |= (imx_data->uhs_mode & SDHCI_CTRL_UHS_MASK); > > ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; > > > > @@ -370,12 +399,37 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) > > new_val &= ~ESDHC_VENDOR_SPEC_VSELECT; > > writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); > > imx_data->uhs_mode = val & SDHCI_CTRL_UHS_MASK; > > - new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); > > - if (val & SDHCI_CTRL_TUNED_CLK) > > - new_val |= ESDHC_MIX_CTRL_SMPCLK_SEL; > > - else > > - new_val &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; > > - writel(new_val , host->ioaddr + ESDHC_MIX_CTRL); > > + if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { > > + new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); > > + if (val & SDHCI_CTRL_TUNED_CLK) > > + new_val |= ESDHC_MIX_CTRL_SMPCLK_SEL; > > + else > > + new_val &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; > > + writel(new_val , host->ioaddr + ESDHC_MIX_CTRL); > > + } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { > > + u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR); > > + u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); > > + new_val = readl(host->ioaddr + ESDHC_TUNING_CTRL); > > + if (val & SDHCI_CTRL_EXEC_TUNING) { > > + new_val |= ESDHC_STD_TUNING_EN | > > + ESDHC_TUNING_START_TAP; > > + v |= ESDHC_MIX_CTRL_EXE_TUNE; > > + m |= ESDHC_MIX_CTRL_FBCLK_SEL; > > + } else { > > + new_val &= ~ESDHC_STD_TUNING_EN; > > + v &= ~ESDHC_MIX_CTRL_EXE_TUNE; > > + m &= ~ESDHC_MIX_CTRL_FBCLK_SEL; > > + } > > + > > + if (val & SDHCI_CTRL_TUNED_CLK) > > + v |= ESDHC_MIX_CTRL_SMPCLK_SEL; > > + else > > + v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; > > + > > + writel(new_val, host->ioaddr + ESDHC_TUNING_CTRL); > > + writel(v, host->ioaddr + SDHCI_ACMD12_ERR); > > + writel(m, host->ioaddr + ESDHC_MIX_CTRL); > > + } > > return; > > case SDHCI_TRANSFER_MODE: > > if ((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) > > @@ -774,7 +828,7 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) > > return esdhc_change_pinstate(host, uhs); > > } > > > > -static const struct sdhci_ops sdhci_esdhc_ops = { > > +static struct sdhci_ops sdhci_esdhc_ops = { > > .read_l = esdhc_readl_le, > > .read_w = esdhc_readw_le, > > .write_l = esdhc_writel_le, > > @@ -786,7 +840,6 @@ static const struct sdhci_ops sdhci_esdhc_ops = { > > .get_ro = esdhc_pltfm_get_ro, > > .platform_bus_width = esdhc_pltfm_bus_width, > > .set_uhs_signaling = esdhc_set_uhs_signaling, > > - .platform_execute_tuning = esdhc_executing_tuning, > > }; > > > > static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { > > @@ -922,6 +975,9 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) > > if (esdhc_is_usdhc(imx_data)) > > writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL); > > > > + if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) > > + sdhci_esdhc_ops.platform_execute_tuning = > > + esdhc_executing_tuning; > > boarddata = &imx_data->boarddata; > > if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { > > if (!host->mmc->parent->platform_data) { > > -- > > 1.7.2.rc3 > > > > -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Fri, Oct 18, 2013 at 06:54:14PM +0800, Dong Aisheng wrote: > The mx6sl supports standard sdhci tuning, then esdhc_executing_tuning > is only needed for mx6q/dl. We introduce is_imx6_usdhc() and > is_imx6sl_usdhc() to handle the difference. > > The standard tuning is enabled by setting ESDHC_TUNE_CTRL_STD_TUNING_EN bit > in new register ESDHC_TUNE_CTRL and operates with new tuning bits > defined in SDHCI_ACMD12_ERR register. > > Note: mx6sl can also work on the old manually tuning mode as mx6q/dl if > not enable standard tuning mode. > > Signed-off-by: Dong Aisheng <b29396@freescale.com> > --- > drivers/mmc/host/sdhci-esdhc-imx.c | 90 +++++++++++++++++++++++++++++------- > 1 files changed, 73 insertions(+), 17 deletions(-) > > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c > index c84c808..a4e0e3b 100644 > --- a/drivers/mmc/host/sdhci-esdhc-imx.c > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c > @@ -51,6 +51,11 @@ > #define ESDHC_TUNE_CTRL_MIN 0 > #define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1) > > +#define ESDHC_TUNING_CTRL 0xcc > +#define ESDHC_STD_TUNING_EN (1 << 24) > +/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ > +#define ESDHC_TUNING_START_TAP 0x1 > + > #define ESDHC_TUNING_BLOCK_PATTERN_LEN 64 > > /* pinctrl state */ > @@ -94,6 +99,12 @@ > * integrated on the i.MX6 series. > */ > #define ESDHC_FLAG_USDHC BIT(3) > +/* The IP supports manual tuning process */ > +#define ESDHC_FLAG_MAN_TUNING BIT(4) > +/* The IP supports standard tuning process */ > +#define ESDHC_FLAG_STD_TUNING BIT(4) BIT(4) for both flags? Shawn > +/* The IP has SDHCI_CAPABILITIES_1 register */ > +#define ESDHC_FLAG_HAVE_CAP1 BIT(5) > > struct esdhc_soc_data { > u32 flags; > @@ -116,7 +127,12 @@ static struct esdhc_soc_data esdhc_imx53_data = { > }; > > static struct esdhc_soc_data usdhc_imx6q_data = { > - .flags = ESDHC_FLAG_USDHC, > + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING, > +}; > + > +static struct esdhc_soc_data usdhc_imx6sl_data = { > + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING > + | ESDHC_FLAG_HAVE_CAP1, > }; > > struct pltfm_imx_data { > @@ -159,6 +175,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { > { .compatible = "fsl,imx35-esdhc", .data = &esdhc_imx35_data, }, > { .compatible = "fsl,imx51-esdhc", .data = &esdhc_imx51_data, }, > { .compatible = "fsl,imx53-esdhc", .data = &esdhc_imx53_data, }, > + { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, }, > { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, }, > { /* sentinel */ } > }; > @@ -222,9 +239,16 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) > } > } > > - if (unlikely(reg == SDHCI_CAPABILITIES_1) && esdhc_is_usdhc(imx_data)) > - val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 > - | SDHCI_SUPPORT_SDR50; > + if (unlikely(reg == SDHCI_CAPABILITIES_1)) { > + if (esdhc_is_usdhc(imx_data)) { > + if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1) > + val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF; > + else > + /* imx6q/dl does not have cap_1 register, fake one */ > + val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 > + | SDHCI_SUPPORT_SDR50; > + } > + } > > if (unlikely(reg == SDHCI_MAX_CURRENT) && esdhc_is_usdhc(imx_data)) { > val = 0; > @@ -331,13 +355,18 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg) > ret |= SDHCI_CTRL_VDD_180; > > if (esdhc_is_usdhc(imx_data)) { > - val = readl(host->ioaddr + ESDHC_MIX_CTRL); > - if (val & ESDHC_MIX_CTRL_EXE_TUNE) > - ret |= SDHCI_CTRL_EXEC_TUNING; > - if (val & ESDHC_MIX_CTRL_SMPCLK_SEL) > - ret |= SDHCI_CTRL_TUNED_CLK; > + if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) > + val = readl(host->ioaddr + ESDHC_MIX_CTRL); > + else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) > + /* the std tuning bits is in ACMD12_ERR for imx6sl */ > + val = readl(host->ioaddr + SDHCI_ACMD12_ERR); > } > > + if (val & ESDHC_MIX_CTRL_EXE_TUNE) > + ret |= SDHCI_CTRL_EXEC_TUNING; > + if (val & ESDHC_MIX_CTRL_SMPCLK_SEL) > + ret |= SDHCI_CTRL_TUNED_CLK; > + > ret |= (imx_data->uhs_mode & SDHCI_CTRL_UHS_MASK); > ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; > > @@ -370,12 +399,37 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) > new_val &= ~ESDHC_VENDOR_SPEC_VSELECT; > writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); > imx_data->uhs_mode = val & SDHCI_CTRL_UHS_MASK; > - new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); > - if (val & SDHCI_CTRL_TUNED_CLK) > - new_val |= ESDHC_MIX_CTRL_SMPCLK_SEL; > - else > - new_val &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; > - writel(new_val , host->ioaddr + ESDHC_MIX_CTRL); > + if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { > + new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); > + if (val & SDHCI_CTRL_TUNED_CLK) > + new_val |= ESDHC_MIX_CTRL_SMPCLK_SEL; > + else > + new_val &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; > + writel(new_val , host->ioaddr + ESDHC_MIX_CTRL); > + } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { > + u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR); > + u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); > + new_val = readl(host->ioaddr + ESDHC_TUNING_CTRL); > + if (val & SDHCI_CTRL_EXEC_TUNING) { > + new_val |= ESDHC_STD_TUNING_EN | > + ESDHC_TUNING_START_TAP; > + v |= ESDHC_MIX_CTRL_EXE_TUNE; > + m |= ESDHC_MIX_CTRL_FBCLK_SEL; > + } else { > + new_val &= ~ESDHC_STD_TUNING_EN; > + v &= ~ESDHC_MIX_CTRL_EXE_TUNE; > + m &= ~ESDHC_MIX_CTRL_FBCLK_SEL; > + } > + > + if (val & SDHCI_CTRL_TUNED_CLK) > + v |= ESDHC_MIX_CTRL_SMPCLK_SEL; > + else > + v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; > + > + writel(new_val, host->ioaddr + ESDHC_TUNING_CTRL); > + writel(v, host->ioaddr + SDHCI_ACMD12_ERR); > + writel(m, host->ioaddr + ESDHC_MIX_CTRL); > + } > return; > case SDHCI_TRANSFER_MODE: > if ((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) > @@ -774,7 +828,7 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) > return esdhc_change_pinstate(host, uhs); > } > > -static const struct sdhci_ops sdhci_esdhc_ops = { > +static struct sdhci_ops sdhci_esdhc_ops = { > .read_l = esdhc_readl_le, > .read_w = esdhc_readw_le, > .write_l = esdhc_writel_le, > @@ -786,7 +840,6 @@ static const struct sdhci_ops sdhci_esdhc_ops = { > .get_ro = esdhc_pltfm_get_ro, > .platform_bus_width = esdhc_pltfm_bus_width, > .set_uhs_signaling = esdhc_set_uhs_signaling, > - .platform_execute_tuning = esdhc_executing_tuning, > }; > > static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { > @@ -922,6 +975,9 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) > if (esdhc_is_usdhc(imx_data)) > writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL); > > + if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) > + sdhci_esdhc_ops.platform_execute_tuning = > + esdhc_executing_tuning; > boarddata = &imx_data->boarddata; > if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { > if (!host->mmc->parent->platform_data) { > -- > 1.7.2.rc3 > > -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index c84c808..a4e0e3b 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -51,6 +51,11 @@ #define ESDHC_TUNE_CTRL_MIN 0 #define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1) +#define ESDHC_TUNING_CTRL 0xcc +#define ESDHC_STD_TUNING_EN (1 << 24) +/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ +#define ESDHC_TUNING_START_TAP 0x1 + #define ESDHC_TUNING_BLOCK_PATTERN_LEN 64 /* pinctrl state */ @@ -94,6 +99,12 @@ * integrated on the i.MX6 series. */ #define ESDHC_FLAG_USDHC BIT(3) +/* The IP supports manual tuning process */ +#define ESDHC_FLAG_MAN_TUNING BIT(4) +/* The IP supports standard tuning process */ +#define ESDHC_FLAG_STD_TUNING BIT(4) +/* The IP has SDHCI_CAPABILITIES_1 register */ +#define ESDHC_FLAG_HAVE_CAP1 BIT(5) struct esdhc_soc_data { u32 flags; @@ -116,7 +127,12 @@ static struct esdhc_soc_data esdhc_imx53_data = { }; static struct esdhc_soc_data usdhc_imx6q_data = { - .flags = ESDHC_FLAG_USDHC, + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING, +}; + +static struct esdhc_soc_data usdhc_imx6sl_data = { + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + | ESDHC_FLAG_HAVE_CAP1, }; struct pltfm_imx_data { @@ -159,6 +175,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { { .compatible = "fsl,imx35-esdhc", .data = &esdhc_imx35_data, }, { .compatible = "fsl,imx51-esdhc", .data = &esdhc_imx51_data, }, { .compatible = "fsl,imx53-esdhc", .data = &esdhc_imx53_data, }, + { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, }, { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, }, { /* sentinel */ } }; @@ -222,9 +239,16 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) } } - if (unlikely(reg == SDHCI_CAPABILITIES_1) && esdhc_is_usdhc(imx_data)) - val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 - | SDHCI_SUPPORT_SDR50; + if (unlikely(reg == SDHCI_CAPABILITIES_1)) { + if (esdhc_is_usdhc(imx_data)) { + if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1) + val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF; + else + /* imx6q/dl does not have cap_1 register, fake one */ + val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 + | SDHCI_SUPPORT_SDR50; + } + } if (unlikely(reg == SDHCI_MAX_CURRENT) && esdhc_is_usdhc(imx_data)) { val = 0; @@ -331,13 +355,18 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg) ret |= SDHCI_CTRL_VDD_180; if (esdhc_is_usdhc(imx_data)) { - val = readl(host->ioaddr + ESDHC_MIX_CTRL); - if (val & ESDHC_MIX_CTRL_EXE_TUNE) - ret |= SDHCI_CTRL_EXEC_TUNING; - if (val & ESDHC_MIX_CTRL_SMPCLK_SEL) - ret |= SDHCI_CTRL_TUNED_CLK; + if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) + val = readl(host->ioaddr + ESDHC_MIX_CTRL); + else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) + /* the std tuning bits is in ACMD12_ERR for imx6sl */ + val = readl(host->ioaddr + SDHCI_ACMD12_ERR); } + if (val & ESDHC_MIX_CTRL_EXE_TUNE) + ret |= SDHCI_CTRL_EXEC_TUNING; + if (val & ESDHC_MIX_CTRL_SMPCLK_SEL) + ret |= SDHCI_CTRL_TUNED_CLK; + ret |= (imx_data->uhs_mode & SDHCI_CTRL_UHS_MASK); ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; @@ -370,12 +399,37 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) new_val &= ~ESDHC_VENDOR_SPEC_VSELECT; writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); imx_data->uhs_mode = val & SDHCI_CTRL_UHS_MASK; - new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); - if (val & SDHCI_CTRL_TUNED_CLK) - new_val |= ESDHC_MIX_CTRL_SMPCLK_SEL; - else - new_val &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; - writel(new_val , host->ioaddr + ESDHC_MIX_CTRL); + if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { + new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); + if (val & SDHCI_CTRL_TUNED_CLK) + new_val |= ESDHC_MIX_CTRL_SMPCLK_SEL; + else + new_val &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; + writel(new_val , host->ioaddr + ESDHC_MIX_CTRL); + } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { + u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR); + u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); + new_val = readl(host->ioaddr + ESDHC_TUNING_CTRL); + if (val & SDHCI_CTRL_EXEC_TUNING) { + new_val |= ESDHC_STD_TUNING_EN | + ESDHC_TUNING_START_TAP; + v |= ESDHC_MIX_CTRL_EXE_TUNE; + m |= ESDHC_MIX_CTRL_FBCLK_SEL; + } else { + new_val &= ~ESDHC_STD_TUNING_EN; + v &= ~ESDHC_MIX_CTRL_EXE_TUNE; + m &= ~ESDHC_MIX_CTRL_FBCLK_SEL; + } + + if (val & SDHCI_CTRL_TUNED_CLK) + v |= ESDHC_MIX_CTRL_SMPCLK_SEL; + else + v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; + + writel(new_val, host->ioaddr + ESDHC_TUNING_CTRL); + writel(v, host->ioaddr + SDHCI_ACMD12_ERR); + writel(m, host->ioaddr + ESDHC_MIX_CTRL); + } return; case SDHCI_TRANSFER_MODE: if ((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) @@ -774,7 +828,7 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) return esdhc_change_pinstate(host, uhs); } -static const struct sdhci_ops sdhci_esdhc_ops = { +static struct sdhci_ops sdhci_esdhc_ops = { .read_l = esdhc_readl_le, .read_w = esdhc_readw_le, .write_l = esdhc_writel_le, @@ -786,7 +840,6 @@ static const struct sdhci_ops sdhci_esdhc_ops = { .get_ro = esdhc_pltfm_get_ro, .platform_bus_width = esdhc_pltfm_bus_width, .set_uhs_signaling = esdhc_set_uhs_signaling, - .platform_execute_tuning = esdhc_executing_tuning, }; static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { @@ -922,6 +975,9 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) if (esdhc_is_usdhc(imx_data)) writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL); + if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) + sdhci_esdhc_ops.platform_execute_tuning = + esdhc_executing_tuning; boarddata = &imx_data->boarddata; if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { if (!host->mmc->parent->platform_data) {
The mx6sl supports standard sdhci tuning, then esdhc_executing_tuning is only needed for mx6q/dl. We introduce is_imx6_usdhc() and is_imx6sl_usdhc() to handle the difference. The standard tuning is enabled by setting ESDHC_TUNE_CTRL_STD_TUNING_EN bit in new register ESDHC_TUNE_CTRL and operates with new tuning bits defined in SDHCI_ACMD12_ERR register. Note: mx6sl can also work on the old manually tuning mode as mx6q/dl if not enable standard tuning mode. Signed-off-by: Dong Aisheng <b29396@freescale.com> --- drivers/mmc/host/sdhci-esdhc-imx.c | 90 +++++++++++++++++++++++++++++------- 1 files changed, 73 insertions(+), 17 deletions(-)