| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572 |
- From 6ca94d2e7dc72b21703e6d9be4e8ec3ad4a26f41 Mon Sep 17 00:00:00 2001
- From: Biwen Li <[email protected]>
- Date: Wed, 17 Apr 2019 18:59:02 +0800
- Subject: [PATCH] sdhc: support layerscape
- This is an integrated patch of sdhc for layerscape
- Signed-off-by: Biwen Li <[email protected]>
- Signed-off-by: Mathew McBride <[email protected]>
- Signed-off-by: Ulf Hansson <[email protected]>
- Signed-off-by: Yangbo Lu <[email protected]>
- Signed-off-by: Yinbo Zhu <[email protected]>
- ---
- drivers/mmc/core/mmc.c | 3 +
- drivers/mmc/host/sdhci-esdhc.h | 25 +++
- drivers/mmc/host/sdhci-of-esdhc.c | 270 ++++++++++++++++++++++++++----
- drivers/mmc/host/sdhci.c | 9 +-
- drivers/mmc/host/sdhci.h | 1 +
- include/linux/mmc/card.h | 1 +
- include/linux/mmc/host.h | 2 +
- 7 files changed, 272 insertions(+), 39 deletions(-)
- --- a/drivers/mmc/core/mmc.c
- +++ b/drivers/mmc/core/mmc.c
- @@ -1174,6 +1174,9 @@ static int mmc_select_hs400(struct mmc_c
- goto out_err;
-
- /* Switch card to DDR */
- + if (host->ops->prepare_ddr_to_hs400)
- + host->ops->prepare_ddr_to_hs400(host);
- +
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BUS_WIDTH,
- EXT_CSD_DDR_BUS_WIDTH_8,
- --- a/drivers/mmc/host/sdhci-esdhc.h
- +++ b/drivers/mmc/host/sdhci-esdhc.h
- @@ -59,7 +59,32 @@
-
- /* Tuning Block Control Register */
- #define ESDHC_TBCTL 0x120
- +#define ESDHC_HS400_WNDW_ADJUST 0x00000040
- +#define ESDHC_HS400_MODE 0x00000010
- #define ESDHC_TB_EN 0x00000004
- +#define ESDHC_TBPTR 0x128
- +
- +/* SD Clock Control Register */
- +#define ESDHC_SDCLKCTL 0x144
- +#define ESDHC_LPBK_CLK_SEL 0x80000000
- +#define ESDHC_CMD_CLK_CTL 0x00008000
- +
- +/* SD Timing Control Register */
- +#define ESDHC_SDTIMNGCTL 0x148
- +#define ESDHC_FLW_CTL_BG 0x00008000
- +
- +/* DLL Config 0 Register */
- +#define ESDHC_DLLCFG0 0x160
- +#define ESDHC_DLL_ENABLE 0x80000000
- +#define ESDHC_DLL_FREQ_SEL 0x08000000
- +
- +/* DLL Config 1 Register */
- +#define ESDHC_DLLCFG1 0x164
- +#define ESDHC_DLL_PD_PULSE_STRETCH_SEL 0x80000000
- +
- +/* DLL Status 0 Register */
- +#define ESDHC_DLLSTAT0 0x170
- +#define ESDHC_DLL_STS_SLV_LOCK 0x08000000
-
- /* Control Register for DMA transfer */
- #define ESDHC_DMA_SYSCTL 0x40c
- --- a/drivers/mmc/host/sdhci-of-esdhc.c
- +++ b/drivers/mmc/host/sdhci-of-esdhc.c
- @@ -30,11 +30,61 @@
- #define VENDOR_V_22 0x12
- #define VENDOR_V_23 0x13
-
- +#define MMC_TIMING_NUM (MMC_TIMING_MMC_HS400 + 1)
- +
- +struct esdhc_clk_fixup {
- + const unsigned int sd_dflt_max_clk;
- + const unsigned int max_clk[MMC_TIMING_NUM];
- +};
- +
- +static const struct esdhc_clk_fixup ls1021a_esdhc_clk = {
- + .sd_dflt_max_clk = 25000000,
- + .max_clk[MMC_TIMING_MMC_HS] = 46500000,
- + .max_clk[MMC_TIMING_SD_HS] = 46500000,
- +};
- +
- +static const struct esdhc_clk_fixup ls1046a_esdhc_clk = {
- + .sd_dflt_max_clk = 25000000,
- + .max_clk[MMC_TIMING_UHS_SDR104] = 167000000,
- + .max_clk[MMC_TIMING_MMC_HS200] = 167000000,
- +};
- +
- +static const struct esdhc_clk_fixup ls1012a_esdhc_clk = {
- + .sd_dflt_max_clk = 25000000,
- + .max_clk[MMC_TIMING_UHS_SDR104] = 125000000,
- + .max_clk[MMC_TIMING_MMC_HS200] = 125000000,
- +};
- +
- +static const struct esdhc_clk_fixup p1010_esdhc_clk = {
- + .sd_dflt_max_clk = 20000000,
- + .max_clk[MMC_TIMING_LEGACY] = 20000000,
- + .max_clk[MMC_TIMING_MMC_HS] = 42000000,
- + .max_clk[MMC_TIMING_SD_HS] = 40000000,
- +};
- +
- +static const struct of_device_id sdhci_esdhc_of_match[] = {
- + { .compatible = "fsl,ls1021a-esdhc", .data = &ls1021a_esdhc_clk},
- + { .compatible = "fsl,ls1046a-esdhc", .data = &ls1046a_esdhc_clk},
- + { .compatible = "fsl,ls1012a-esdhc", .data = &ls1012a_esdhc_clk},
- + { .compatible = "fsl,p1010-esdhc", .data = &p1010_esdhc_clk},
- + { .compatible = "fsl,mpc8379-esdhc" },
- + { .compatible = "fsl,mpc8536-esdhc" },
- + { .compatible = "fsl,esdhc" },
- + { }
- +};
- +MODULE_DEVICE_TABLE(of, sdhci_esdhc_of_match);
- +
- struct sdhci_esdhc {
- u8 vendor_ver;
- u8 spec_ver;
- bool quirk_incorrect_hostver;
- + bool quirk_limited_clk_division;
- + bool quirk_unreliable_pulse_detection;
- + bool quirk_fixup_tuning;
- + bool quirk_incorrect_delay_chain;
- unsigned int peripheral_clock;
- + const struct esdhc_clk_fixup *clk_fixup;
- + u32 div_ratio;
- };
-
- /**
- @@ -495,13 +545,20 @@ static void esdhc_clock_enable(struct sd
- }
- }
-
- +static struct soc_device_attribute soc_incorrect_delay_chain[] = {
- + { .family = "QorIQ LX2160A", .revision = "1.0", },
- + { },
- +};
- +
- static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
- {
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
- int pre_div = 1;
- int div = 1;
- + int division;
- ktime_t timeout;
- + long fixup = 0;
- u32 temp;
-
- host->mmc->actual_clock = 0;
- @@ -515,27 +572,14 @@ static void esdhc_of_set_clock(struct sd
- if (esdhc->vendor_ver < VENDOR_V_23)
- pre_div = 2;
-
- - /*
- - * Limit SD clock to 167MHz for ls1046a according to its datasheet
- - */
- - if (clock > 167000000 &&
- - of_find_compatible_node(NULL, NULL, "fsl,ls1046a-esdhc"))
- - clock = 167000000;
- + if (host->mmc->card && mmc_card_sd(host->mmc->card) &&
- + esdhc->clk_fixup && host->mmc->ios.timing == MMC_TIMING_LEGACY)
- + fixup = esdhc->clk_fixup->sd_dflt_max_clk;
- + else if (esdhc->clk_fixup)
- + fixup = esdhc->clk_fixup->max_clk[host->mmc->ios.timing];
-
- - /*
- - * Limit SD clock to 125MHz for ls1012a according to its datasheet
- - */
- - if (clock > 125000000 &&
- - of_find_compatible_node(NULL, NULL, "fsl,ls1012a-esdhc"))
- - clock = 125000000;
- -
- - /* Workaround to reduce the clock frequency for p1010 esdhc */
- - if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) {
- - if (clock > 20000000)
- - clock -= 5000000;
- - if (clock > 40000000)
- - clock -= 5000000;
- - }
- + if (fixup && clock > fixup)
- + clock = fixup;
-
- temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
- temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN |
- @@ -548,9 +592,30 @@ static void esdhc_of_set_clock(struct sd
- while (host->max_clk / pre_div / div > clock && div < 16)
- div++;
-
- + if (esdhc->quirk_limited_clk_division &&
- + clock == MMC_HS200_MAX_DTR &&
- + (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 ||
- + host->flags & SDHCI_HS400_TUNING)) {
- + division = pre_div * div;
- + if (division <= 4) {
- + pre_div = 4;
- + div = 1;
- + } else if (division <= 8) {
- + pre_div = 4;
- + div = 2;
- + } else if (division <= 12) {
- + pre_div = 4;
- + div = 3;
- + } else {
- + pr_warn("%s: using upsupported clock division.\n",
- + mmc_hostname(host->mmc));
- + }
- + }
- +
- dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
- clock, host->max_clk / pre_div / div);
- host->mmc->actual_clock = host->max_clk / pre_div / div;
- + esdhc->div_ratio = pre_div * div;
- pre_div >>= 1;
- div--;
-
- @@ -560,6 +625,29 @@ static void esdhc_of_set_clock(struct sd
- | (pre_div << ESDHC_PREDIV_SHIFT));
- sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
-
- + if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 &&
- + clock == MMC_HS200_MAX_DTR) {
- + temp = sdhci_readl(host, ESDHC_TBCTL);
- + sdhci_writel(host, temp | ESDHC_HS400_MODE, ESDHC_TBCTL);
- + temp = sdhci_readl(host, ESDHC_SDCLKCTL);
- + sdhci_writel(host, temp | ESDHC_CMD_CLK_CTL, ESDHC_SDCLKCTL);
- + esdhc_clock_enable(host, true);
- +
- + temp = sdhci_readl(host, ESDHC_DLLCFG0);
- + temp |= ESDHC_DLL_ENABLE;
- + if (host->mmc->actual_clock == MMC_HS200_MAX_DTR ||
- + esdhc->quirk_incorrect_delay_chain == false)
- + temp |= ESDHC_DLL_FREQ_SEL;
- + sdhci_writel(host, temp, ESDHC_DLLCFG0);
- + temp = sdhci_readl(host, ESDHC_TBCTL);
- + sdhci_writel(host, temp | ESDHC_HS400_WNDW_ADJUST, ESDHC_TBCTL);
- +
- + esdhc_clock_enable(host, false);
- + temp = sdhci_readl(host, ESDHC_DMA_SYSCTL);
- + temp |= ESDHC_FLUSH_ASYNC_FIFO;
- + sdhci_writel(host, temp, ESDHC_DMA_SYSCTL);
- + }
- +
- /* Wait max 20 ms */
- timeout = ktime_add_ms(ktime_get(), 20);
- while (1) {
- @@ -575,6 +663,7 @@ static void esdhc_of_set_clock(struct sd
- udelay(10);
- }
-
- + temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
- temp |= ESDHC_CLOCK_SDCLKEN;
- sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
- }
- @@ -603,6 +692,8 @@ static void esdhc_pltfm_set_bus_width(st
-
- static void esdhc_reset(struct sdhci_host *host, u8 mask)
- {
- + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
- u32 val;
-
- sdhci_reset(host, mask);
- @@ -617,6 +708,12 @@ static void esdhc_reset(struct sdhci_hos
- val = sdhci_readl(host, ESDHC_TBCTL);
- val &= ~ESDHC_TB_EN;
- sdhci_writel(host, val, ESDHC_TBCTL);
- +
- + if (esdhc->quirk_unreliable_pulse_detection) {
- + val = sdhci_readl(host, ESDHC_DLLCFG1);
- + val &= ~ESDHC_DLL_PD_PULSE_STRETCH_SEL;
- + sdhci_writel(host, val, ESDHC_DLLCFG1);
- + }
- }
- }
-
- @@ -628,6 +725,7 @@ static void esdhc_reset(struct sdhci_hos
- static const struct of_device_id scfg_device_ids[] = {
- { .compatible = "fsl,t1040-scfg", },
- { .compatible = "fsl,ls1012a-scfg", },
- + { .compatible = "fsl,ls1043a-scfg", },
- { .compatible = "fsl,ls1046a-scfg", },
- {}
- };
- @@ -690,23 +788,91 @@ static int esdhc_signal_voltage_switch(s
- }
- }
-
- -static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
- +static struct soc_device_attribute soc_fixup_tuning[] = {
- + { .family = "QorIQ T1040", .revision = "1.0", },
- + { .family = "QorIQ T2080", .revision = "1.0", },
- + { .family = "QorIQ T1023", .revision = "1.0", },
- + { .family = "QorIQ LS1021A", .revision = "1.0", },
- + { .family = "QorIQ LS1080A", .revision = "1.0", },
- + { .family = "QorIQ LS2080A", .revision = "1.0", },
- + { .family = "QorIQ LS1012A", .revision = "1.0", },
- + { .family = "QorIQ LS1043A", .revision = "1.*", },
- + { .family = "QorIQ LS1046A", .revision = "1.0", },
- + { },
- +};
- +
- +static void esdhc_tuning_block_enable(struct sdhci_host *host, bool enable)
- {
- - struct sdhci_host *host = mmc_priv(mmc);
- u32 val;
-
- - /* Use tuning block for tuning procedure */
- esdhc_clock_enable(host, false);
- +
- val = sdhci_readl(host, ESDHC_DMA_SYSCTL);
- val |= ESDHC_FLUSH_ASYNC_FIFO;
- sdhci_writel(host, val, ESDHC_DMA_SYSCTL);
-
- val = sdhci_readl(host, ESDHC_TBCTL);
- - val |= ESDHC_TB_EN;
- + if (enable)
- + val |= ESDHC_TB_EN;
- + else
- + val &= ~ESDHC_TB_EN;
- sdhci_writel(host, val, ESDHC_TBCTL);
- +
- esdhc_clock_enable(host, true);
- +}
- +
- +static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
- +{
- + struct sdhci_host *host = mmc_priv(mmc);
- + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
- + bool hs400_tuning;
- + u32 val;
- + int ret;
- +
- + if (esdhc->quirk_limited_clk_division &&
- + host->flags & SDHCI_HS400_TUNING)
- + esdhc_of_set_clock(host, host->clock);
- +
- + esdhc_tuning_block_enable(host, true);
- +
- + hs400_tuning = host->flags & SDHCI_HS400_TUNING;
- + ret = sdhci_execute_tuning(mmc, opcode);
- +
- + if (hs400_tuning) {
- + val = sdhci_readl(host, ESDHC_SDTIMNGCTL);
- + val |= ESDHC_FLW_CTL_BG;
- + sdhci_writel(host, val, ESDHC_SDTIMNGCTL);
- + }
-
- - return sdhci_execute_tuning(mmc, opcode);
- + if (host->tuning_err == -EAGAIN && esdhc->quirk_fixup_tuning) {
- +
- + /* program TBPTR[TB_WNDW_END_PTR] = 3*DIV_RATIO and
- + * program TBPTR[TB_WNDW_START_PTR] = 5*DIV_RATIO
- + */
- + val = sdhci_readl(host, ESDHC_TBPTR);
- + val = (val & ~((0x7f << 8) | 0x7f)) |
- + (3 * esdhc->div_ratio) | ((5 * esdhc->div_ratio) << 8);
- + sdhci_writel(host, val, ESDHC_TBPTR);
- +
- + /* program the software tuning mode by setting
- + * TBCTL[TB_MODE]=2'h3
- + */
- + val = sdhci_readl(host, ESDHC_TBCTL);
- + val |= 0x3;
- + sdhci_writel(host, val, ESDHC_TBCTL);
- + sdhci_execute_tuning(mmc, opcode);
- + }
- + return ret;
- +}
- +
- +static void esdhc_set_uhs_signaling(struct sdhci_host *host,
- + unsigned int timing)
- +{
- + if (timing == MMC_TIMING_MMC_HS400)
- + esdhc_tuning_block_enable(host, true);
- + else
- + sdhci_set_uhs_signaling(host, timing);
- }
-
- #ifdef CONFIG_PM_SLEEP
- @@ -755,7 +921,7 @@ static const struct sdhci_ops sdhci_esdh
- .adma_workaround = esdhc_of_adma_workaround,
- .set_bus_width = esdhc_pltfm_set_bus_width,
- .reset = esdhc_reset,
- - .set_uhs_signaling = sdhci_set_uhs_signaling,
- + .set_uhs_signaling = esdhc_set_uhs_signaling,
- };
-
- static const struct sdhci_ops sdhci_esdhc_le_ops = {
- @@ -772,7 +938,7 @@ static const struct sdhci_ops sdhci_esdh
- .adma_workaround = esdhc_of_adma_workaround,
- .set_bus_width = esdhc_pltfm_set_bus_width,
- .reset = esdhc_reset,
- - .set_uhs_signaling = sdhci_set_uhs_signaling,
- + .set_uhs_signaling = esdhc_set_uhs_signaling,
- };
-
- static const struct sdhci_pltfm_data sdhci_esdhc_be_pdata = {
- @@ -798,8 +964,20 @@ static struct soc_device_attribute soc_i
- { },
- };
-
- +static struct soc_device_attribute soc_fixup_sdhc_clkdivs[] = {
- + { .family = "QorIQ LX2160A", .revision = "1.0", },
- + { .family = "QorIQ LX2160A", .revision = "2.0", },
- + { },
- +};
- +
- +static struct soc_device_attribute soc_unreliable_pulse_detection[] = {
- + { .family = "QorIQ LX2160A", .revision = "1.0", },
- + { },
- +};
- +
- static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
- {
- + const struct of_device_id *match;
- struct sdhci_pltfm_host *pltfm_host;
- struct sdhci_esdhc *esdhc;
- struct device_node *np;
- @@ -819,6 +997,24 @@ static void esdhc_init(struct platform_d
- else
- esdhc->quirk_incorrect_hostver = false;
-
- + if (soc_device_match(soc_fixup_sdhc_clkdivs))
- + esdhc->quirk_limited_clk_division = true;
- + else
- + esdhc->quirk_limited_clk_division = false;
- +
- + if (soc_device_match(soc_unreliable_pulse_detection))
- + esdhc->quirk_unreliable_pulse_detection = true;
- + else
- + esdhc->quirk_unreliable_pulse_detection = false;
- +
- + if (soc_device_match(soc_incorrect_delay_chain))
- + esdhc->quirk_incorrect_delay_chain = true;
- + else
- + esdhc->quirk_incorrect_delay_chain = false;
- +
- + match = of_match_node(sdhci_esdhc_of_match, pdev->dev.of_node);
- + if (match)
- + esdhc->clk_fixup = match->data;
- np = pdev->dev.of_node;
- clk = of_clk_get(np, 0);
- if (!IS_ERR(clk)) {
- @@ -846,6 +1042,12 @@ static void esdhc_init(struct platform_d
- }
- }
-
- +static int esdhc_prepare_ddr_to_hs400(struct mmc_host *mmc)
- +{
- + esdhc_tuning_block_enable(mmc_priv(mmc), false);
- + return 0;
- +}
- +
- static int sdhci_esdhc_probe(struct platform_device *pdev)
- {
- struct sdhci_host *host;
- @@ -869,6 +1071,7 @@ static int sdhci_esdhc_probe(struct plat
- host->mmc_host_ops.start_signal_voltage_switch =
- esdhc_signal_voltage_switch;
- host->mmc_host_ops.execute_tuning = esdhc_execute_tuning;
- + host->mmc_host_ops.prepare_ddr_to_hs400 = esdhc_prepare_ddr_to_hs400;
- host->tuning_delay = 1;
-
- esdhc_init(pdev, host);
- @@ -877,6 +1080,11 @@ static int sdhci_esdhc_probe(struct plat
-
- pltfm_host = sdhci_priv(host);
- esdhc = sdhci_pltfm_priv(pltfm_host);
- + if (soc_device_match(soc_fixup_tuning))
- + esdhc->quirk_fixup_tuning = true;
- + else
- + esdhc->quirk_fixup_tuning = false;
- +
- if (esdhc->vendor_ver == VENDOR_V_22)
- host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
-
- @@ -923,14 +1131,6 @@ static int sdhci_esdhc_probe(struct plat
- return ret;
- }
-
- -static const struct of_device_id sdhci_esdhc_of_match[] = {
- - { .compatible = "fsl,mpc8379-esdhc" },
- - { .compatible = "fsl,mpc8536-esdhc" },
- - { .compatible = "fsl,esdhc" },
- - { }
- -};
- -MODULE_DEVICE_TABLE(of, sdhci_esdhc_of_match);
- -
- static struct platform_driver sdhci_esdhc_driver = {
- .driver = {
- .name = "sdhci-esdhc",
- --- a/drivers/mmc/host/sdhci.c
- +++ b/drivers/mmc/host/sdhci.c
- @@ -2148,7 +2148,7 @@ static void sdhci_send_tuning(struct sdh
-
- }
-
- -static void __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
- +static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
- {
- int i;
-
- @@ -2165,13 +2165,13 @@ static void __sdhci_execute_tuning(struc
- pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n",
- mmc_hostname(host->mmc));
- sdhci_abort_tuning(host, opcode);
- - return;
- + return -ETIMEDOUT;
- }
-
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) {
- if (ctrl & SDHCI_CTRL_TUNED_CLK)
- - return; /* Success! */
- + return 0; /* Success! */
- break;
- }
-
- @@ -2183,6 +2183,7 @@ static void __sdhci_execute_tuning(struc
- pr_info("%s: Tuning failed, falling back to fixed sampling clock\n",
- mmc_hostname(host->mmc));
- sdhci_reset_tuning(host);
- + return -EAGAIN;
- }
-
- int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
- @@ -2244,7 +2245,7 @@ int sdhci_execute_tuning(struct mmc_host
-
- sdhci_start_tuning(host);
-
- - __sdhci_execute_tuning(host, opcode);
- + host->tuning_err = __sdhci_execute_tuning(host, opcode);
-
- sdhci_end_tuning(host);
- out:
- --- a/drivers/mmc/host/sdhci.h
- +++ b/drivers/mmc/host/sdhci.h
- @@ -545,6 +545,7 @@ struct sdhci_host {
-
- unsigned int tuning_count; /* Timer count for re-tuning */
- unsigned int tuning_mode; /* Re-tuning mode supported by host */
- + unsigned int tuning_err; /* Error code for re-tuning */
- #define SDHCI_TUNING_MODE_1 0
- #define SDHCI_TUNING_MODE_2 1
- #define SDHCI_TUNING_MODE_3 2
- --- a/include/linux/mmc/card.h
- +++ b/include/linux/mmc/card.h
- @@ -156,6 +156,7 @@ struct sd_switch_caps {
- #define UHS_DDR50_MAX_DTR 50000000
- #define UHS_SDR25_MAX_DTR UHS_DDR50_MAX_DTR
- #define UHS_SDR12_MAX_DTR 25000000
- +#define DEFAULT_SPEED_MAX_DTR UHS_SDR12_MAX_DTR
- unsigned int sd3_bus_mode;
- #define UHS_SDR12_BUS_SPEED 0
- #define HIGH_SPEED_BUS_SPEED 1
- --- a/include/linux/mmc/host.h
- +++ b/include/linux/mmc/host.h
- @@ -145,6 +145,8 @@ struct mmc_host_ops {
-
- /* Prepare HS400 target operating frequency depending host driver */
- int (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
- + int (*prepare_ddr_to_hs400)(struct mmc_host *host);
- +
- /* Prepare enhanced strobe depending host driver */
- void (*hs400_enhanced_strobe)(struct mmc_host *host,
- struct mmc_ios *ios);
|