diff options
author | Dong Aisheng <b29396@freescale.com> | 2013-10-18 07:48:43 -0400 |
---|---|---|
committer | Chris Ball <chris@printf.net> | 2013-10-21 15:57:58 -0400 |
commit | 6e9fd28e1f2422e8e5ad3c9871c952aad6a7e5ca (patch) | |
tree | 0dd686b2c1988ca94a4f9a963fb5eb4ec3367775 | |
parent | f47c4bbfa283df2dfd23c422c53f96d12005bbf6 (diff) |
mmc: sdhci-esdhc-imx: add std tuning support for mx6sl
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>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r-- | 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 c84c808ab00b..3b9c94f74ed0 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c | |||
@@ -51,6 +51,11 @@ | |||
51 | #define ESDHC_TUNE_CTRL_MIN 0 | 51 | #define ESDHC_TUNE_CTRL_MIN 0 |
52 | #define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1) | 52 | #define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1) |
53 | 53 | ||
54 | #define ESDHC_TUNING_CTRL 0xcc | ||
55 | #define ESDHC_STD_TUNING_EN (1 << 24) | ||
56 | /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ | ||
57 | #define ESDHC_TUNING_START_TAP 0x1 | ||
58 | |||
54 | #define ESDHC_TUNING_BLOCK_PATTERN_LEN 64 | 59 | #define ESDHC_TUNING_BLOCK_PATTERN_LEN 64 |
55 | 60 | ||
56 | /* pinctrl state */ | 61 | /* pinctrl state */ |
@@ -94,6 +99,12 @@ | |||
94 | * integrated on the i.MX6 series. | 99 | * integrated on the i.MX6 series. |
95 | */ | 100 | */ |
96 | #define ESDHC_FLAG_USDHC BIT(3) | 101 | #define ESDHC_FLAG_USDHC BIT(3) |
102 | /* The IP supports manual tuning process */ | ||
103 | #define ESDHC_FLAG_MAN_TUNING BIT(4) | ||
104 | /* The IP supports standard tuning process */ | ||
105 | #define ESDHC_FLAG_STD_TUNING BIT(5) | ||
106 | /* The IP has SDHCI_CAPABILITIES_1 register */ | ||
107 | #define ESDHC_FLAG_HAVE_CAP1 BIT(6) | ||
97 | 108 | ||
98 | struct esdhc_soc_data { | 109 | struct esdhc_soc_data { |
99 | u32 flags; | 110 | u32 flags; |
@@ -116,7 +127,12 @@ static struct esdhc_soc_data esdhc_imx53_data = { | |||
116 | }; | 127 | }; |
117 | 128 | ||
118 | static struct esdhc_soc_data usdhc_imx6q_data = { | 129 | static struct esdhc_soc_data usdhc_imx6q_data = { |
119 | .flags = ESDHC_FLAG_USDHC, | 130 | .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING, |
131 | }; | ||
132 | |||
133 | static struct esdhc_soc_data usdhc_imx6sl_data = { | ||
134 | .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING | ||
135 | | ESDHC_FLAG_HAVE_CAP1, | ||
120 | }; | 136 | }; |
121 | 137 | ||
122 | struct pltfm_imx_data { | 138 | struct pltfm_imx_data { |
@@ -159,6 +175,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { | |||
159 | { .compatible = "fsl,imx35-esdhc", .data = &esdhc_imx35_data, }, | 175 | { .compatible = "fsl,imx35-esdhc", .data = &esdhc_imx35_data, }, |
160 | { .compatible = "fsl,imx51-esdhc", .data = &esdhc_imx51_data, }, | 176 | { .compatible = "fsl,imx51-esdhc", .data = &esdhc_imx51_data, }, |
161 | { .compatible = "fsl,imx53-esdhc", .data = &esdhc_imx53_data, }, | 177 | { .compatible = "fsl,imx53-esdhc", .data = &esdhc_imx53_data, }, |
178 | { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, }, | ||
162 | { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, }, | 179 | { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, }, |
163 | { /* sentinel */ } | 180 | { /* sentinel */ } |
164 | }; | 181 | }; |
@@ -222,9 +239,16 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) | |||
222 | } | 239 | } |
223 | } | 240 | } |
224 | 241 | ||
225 | if (unlikely(reg == SDHCI_CAPABILITIES_1) && esdhc_is_usdhc(imx_data)) | 242 | if (unlikely(reg == SDHCI_CAPABILITIES_1)) { |
226 | val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 | 243 | if (esdhc_is_usdhc(imx_data)) { |
227 | | SDHCI_SUPPORT_SDR50; | 244 | if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1) |
245 | val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF; | ||
246 | else | ||
247 | /* imx6q/dl does not have cap_1 register, fake one */ | ||
248 | val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 | ||
249 | | SDHCI_SUPPORT_SDR50; | ||
250 | } | ||
251 | } | ||
228 | 252 | ||
229 | if (unlikely(reg == SDHCI_MAX_CURRENT) && esdhc_is_usdhc(imx_data)) { | 253 | if (unlikely(reg == SDHCI_MAX_CURRENT) && esdhc_is_usdhc(imx_data)) { |
230 | val = 0; | 254 | val = 0; |
@@ -331,13 +355,18 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg) | |||
331 | ret |= SDHCI_CTRL_VDD_180; | 355 | ret |= SDHCI_CTRL_VDD_180; |
332 | 356 | ||
333 | if (esdhc_is_usdhc(imx_data)) { | 357 | if (esdhc_is_usdhc(imx_data)) { |
334 | val = readl(host->ioaddr + ESDHC_MIX_CTRL); | 358 | if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) |
335 | if (val & ESDHC_MIX_CTRL_EXE_TUNE) | 359 | val = readl(host->ioaddr + ESDHC_MIX_CTRL); |
336 | ret |= SDHCI_CTRL_EXEC_TUNING; | 360 | else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) |
337 | if (val & ESDHC_MIX_CTRL_SMPCLK_SEL) | 361 | /* the std tuning bits is in ACMD12_ERR for imx6sl */ |
338 | ret |= SDHCI_CTRL_TUNED_CLK; | 362 | val = readl(host->ioaddr + SDHCI_ACMD12_ERR); |
339 | } | 363 | } |
340 | 364 | ||
365 | if (val & ESDHC_MIX_CTRL_EXE_TUNE) | ||
366 | ret |= SDHCI_CTRL_EXEC_TUNING; | ||
367 | if (val & ESDHC_MIX_CTRL_SMPCLK_SEL) | ||
368 | ret |= SDHCI_CTRL_TUNED_CLK; | ||
369 | |||
341 | ret |= (imx_data->uhs_mode & SDHCI_CTRL_UHS_MASK); | 370 | ret |= (imx_data->uhs_mode & SDHCI_CTRL_UHS_MASK); |
342 | ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; | 371 | ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; |
343 | 372 | ||
@@ -370,12 +399,37 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) | |||
370 | new_val &= ~ESDHC_VENDOR_SPEC_VSELECT; | 399 | new_val &= ~ESDHC_VENDOR_SPEC_VSELECT; |
371 | writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); | 400 | writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); |
372 | imx_data->uhs_mode = val & SDHCI_CTRL_UHS_MASK; | 401 | imx_data->uhs_mode = val & SDHCI_CTRL_UHS_MASK; |
373 | new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); | 402 | if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { |
374 | if (val & SDHCI_CTRL_TUNED_CLK) | 403 | new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); |
375 | new_val |= ESDHC_MIX_CTRL_SMPCLK_SEL; | 404 | if (val & SDHCI_CTRL_TUNED_CLK) |
376 | else | 405 | new_val |= ESDHC_MIX_CTRL_SMPCLK_SEL; |
377 | new_val &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; | 406 | else |
378 | writel(new_val , host->ioaddr + ESDHC_MIX_CTRL); | 407 | new_val &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; |
408 | writel(new_val , host->ioaddr + ESDHC_MIX_CTRL); | ||
409 | } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { | ||
410 | u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR); | ||
411 | u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); | ||
412 | new_val = readl(host->ioaddr + ESDHC_TUNING_CTRL); | ||
413 | if (val & SDHCI_CTRL_EXEC_TUNING) { | ||
414 | new_val |= ESDHC_STD_TUNING_EN | | ||
415 | ESDHC_TUNING_START_TAP; | ||
416 | v |= ESDHC_MIX_CTRL_EXE_TUNE; | ||
417 | m |= ESDHC_MIX_CTRL_FBCLK_SEL; | ||
418 | } else { | ||
419 | new_val &= ~ESDHC_STD_TUNING_EN; | ||
420 | v &= ~ESDHC_MIX_CTRL_EXE_TUNE; | ||
421 | m &= ~ESDHC_MIX_CTRL_FBCLK_SEL; | ||
422 | } | ||
423 | |||
424 | if (val & SDHCI_CTRL_TUNED_CLK) | ||
425 | v |= ESDHC_MIX_CTRL_SMPCLK_SEL; | ||
426 | else | ||
427 | v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; | ||
428 | |||
429 | writel(new_val, host->ioaddr + ESDHC_TUNING_CTRL); | ||
430 | writel(v, host->ioaddr + SDHCI_ACMD12_ERR); | ||
431 | writel(m, host->ioaddr + ESDHC_MIX_CTRL); | ||
432 | } | ||
379 | return; | 433 | return; |
380 | case SDHCI_TRANSFER_MODE: | 434 | case SDHCI_TRANSFER_MODE: |
381 | if ((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) | 435 | 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) | |||
774 | return esdhc_change_pinstate(host, uhs); | 828 | return esdhc_change_pinstate(host, uhs); |
775 | } | 829 | } |
776 | 830 | ||
777 | static const struct sdhci_ops sdhci_esdhc_ops = { | 831 | static struct sdhci_ops sdhci_esdhc_ops = { |
778 | .read_l = esdhc_readl_le, | 832 | .read_l = esdhc_readl_le, |
779 | .read_w = esdhc_readw_le, | 833 | .read_w = esdhc_readw_le, |
780 | .write_l = esdhc_writel_le, | 834 | .write_l = esdhc_writel_le, |
@@ -786,7 +840,6 @@ static const struct sdhci_ops sdhci_esdhc_ops = { | |||
786 | .get_ro = esdhc_pltfm_get_ro, | 840 | .get_ro = esdhc_pltfm_get_ro, |
787 | .platform_bus_width = esdhc_pltfm_bus_width, | 841 | .platform_bus_width = esdhc_pltfm_bus_width, |
788 | .set_uhs_signaling = esdhc_set_uhs_signaling, | 842 | .set_uhs_signaling = esdhc_set_uhs_signaling, |
789 | .platform_execute_tuning = esdhc_executing_tuning, | ||
790 | }; | 843 | }; |
791 | 844 | ||
792 | static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { | 845 | static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { |
@@ -922,6 +975,9 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) | |||
922 | if (esdhc_is_usdhc(imx_data)) | 975 | if (esdhc_is_usdhc(imx_data)) |
923 | writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL); | 976 | writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL); |
924 | 977 | ||
978 | if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) | ||
979 | sdhci_esdhc_ops.platform_execute_tuning = | ||
980 | esdhc_executing_tuning; | ||
925 | boarddata = &imx_data->boarddata; | 981 | boarddata = &imx_data->boarddata; |
926 | if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { | 982 | if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { |
927 | if (!host->mmc->parent->platform_data) { | 983 | if (!host->mmc->parent->platform_data) { |