* [v2, 1/2] mmc: sdhci-of-esdhc: fix esdhc_reset() for different controller versions
@ 2020-01-08 4:07 Yangbo Lu
2020-01-08 4:07 ` [v2, 2/2] mmc: sdhci-of-esdhc: fix clock setting " Yangbo Lu
2020-01-16 14:39 ` [v2, 1/2] mmc: sdhci-of-esdhc: fix esdhc_reset() " Ulf Hansson
0 siblings, 2 replies; 4+ messages in thread
From: Yangbo Lu @ 2020-01-08 4:07 UTC (permalink / raw)
To: linux-mmc, Ulf Hansson, Adrian Hunter; +Cc: Yangbo Lu
This patch is to fix operating in esdhc_reset() for different
controller versions, and to add bus-width restoring after data
reset for eSDHC (verdor version <= 2.2).
Also add annotation for understanding.
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
---
Changes for v2:
- Added ACK from Adrian.
- Used preferred style for comments.
---
drivers/mmc/host/sdhci-of-esdhc.c | 43 +++++++++++++++++++++++++++++++++++----
1 file changed, 39 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index cd3b676..1110f90 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -758,23 +758,58 @@ 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;
+ u32 val, bus_width = 0;
+ /*
+ * Add delay to make sure all the DMA transfers are finished
+ * for quirk.
+ */
if (esdhc->quirk_delay_before_data_reset &&
(mask & SDHCI_RESET_DATA) &&
(host->flags & SDHCI_REQ_USE_DMA))
mdelay(5);
+ /*
+ * Save bus-width for eSDHC whose vendor version is 2.2
+ * or lower for data reset.
+ */
+ if ((mask & SDHCI_RESET_DATA) &&
+ (esdhc->vendor_ver <= VENDOR_V_22)) {
+ val = sdhci_readl(host, ESDHC_PROCTL);
+ bus_width = val & ESDHC_CTRL_BUSWIDTH_MASK;
+ }
+
sdhci_reset(host, mask);
- sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+ /*
+ * Restore bus-width setting and interrupt registers for eSDHC
+ * whose vendor version is 2.2 or lower for data reset.
+ */
+ if ((mask & SDHCI_RESET_DATA) &&
+ (esdhc->vendor_ver <= VENDOR_V_22)) {
+ val = sdhci_readl(host, ESDHC_PROCTL);
+ val &= ~ESDHC_CTRL_BUSWIDTH_MASK;
+ val |= bus_width;
+ sdhci_writel(host, val, ESDHC_PROCTL);
+
+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+ }
- if (mask & SDHCI_RESET_ALL) {
+ /*
+ * Some bits have to be cleaned manually for eSDHC whose spec
+ * version is higher than 3.0 for all reset.
+ */
+ if ((mask & SDHCI_RESET_ALL) &&
+ (esdhc->spec_ver >= SDHCI_SPEC_300)) {
val = sdhci_readl(host, ESDHC_TBCTL);
val &= ~ESDHC_TB_EN;
sdhci_writel(host, val, ESDHC_TBCTL);
+ /*
+ * Initialize eSDHC_DLLCFG1[DLL_PD_PULSE_STRETCH_SEL] to
+ * 0 for quirk.
+ */
if (esdhc->quirk_unreliable_pulse_detection) {
val = sdhci_readl(host, ESDHC_DLLCFG1);
val &= ~ESDHC_DLL_PD_PULSE_STRETCH_SEL;
--
2.7.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [v2, 2/2] mmc: sdhci-of-esdhc: fix clock setting for different controller versions
2020-01-08 4:07 [v2, 1/2] mmc: sdhci-of-esdhc: fix esdhc_reset() for different controller versions Yangbo Lu
@ 2020-01-08 4:07 ` Yangbo Lu
2020-01-16 14:39 ` Ulf Hansson
2020-01-16 14:39 ` [v2, 1/2] mmc: sdhci-of-esdhc: fix esdhc_reset() " Ulf Hansson
1 sibling, 1 reply; 4+ messages in thread
From: Yangbo Lu @ 2020-01-08 4:07 UTC (permalink / raw)
To: linux-mmc, Ulf Hansson, Adrian Hunter; +Cc: Yangbo Lu
This patch is to fix clock setting code for different controller
versions. Two of HW changes after vendor version 2.2 are removing
PEREN/HCKEN/IPGEN bits in system control register, and adding SD
clock stable bit in present state register. This patch cleans up
related code too.
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
Changes for v2:
- Used preferred style for comments.
---
drivers/mmc/host/sdhci-of-esdhc.c | 128 +++++++++++++++++++++-----------------
1 file changed, 72 insertions(+), 56 deletions(-)
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 1110f90..6a58cf9 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -562,32 +562,46 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
static void esdhc_clock_enable(struct sdhci_host *host, bool enable)
{
- u32 val;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
ktime_t timeout;
+ u32 val, clk_en;
+
+ clk_en = ESDHC_CLOCK_SDCLKEN;
+
+ /*
+ * IPGEN/HCKEN/PEREN bits exist on eSDHC whose vendor version
+ * is 2.2 or lower.
+ */
+ if (esdhc->vendor_ver <= VENDOR_V_22)
+ clk_en |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN |
+ ESDHC_CLOCK_PEREN);
val = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
if (enable)
- val |= ESDHC_CLOCK_SDCLKEN;
+ val |= clk_en;
else
- val &= ~ESDHC_CLOCK_SDCLKEN;
+ val &= ~clk_en;
sdhci_writel(host, val, ESDHC_SYSTEM_CONTROL);
- /* Wait max 20 ms */
+ /*
+ * Wait max 20 ms. If vendor version is 2.2 or lower, do not
+ * wait clock stable bit which does not exist.
+ */
timeout = ktime_add_ms(ktime_get(), 20);
- val = ESDHC_CLOCK_STABLE;
- while (1) {
+ while (esdhc->vendor_ver > VENDOR_V_22) {
bool timedout = ktime_after(ktime_get(), timeout);
- if (sdhci_readl(host, ESDHC_PRSSTAT) & val)
+ if (sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)
break;
if (timedout) {
pr_err("%s: Internal clock never stabilised.\n",
mmc_hostname(host->mmc));
break;
}
- udelay(10);
+ usleep_range(10, 20);
}
}
@@ -621,77 +635,97 @@ 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;
+ unsigned int pre_div = 1, div = 1;
+ unsigned int clock_fixup = 0;
ktime_t timeout;
- long fixup = 0;
u32 temp;
- host->mmc->actual_clock = 0;
-
if (clock == 0) {
+ host->mmc->actual_clock = 0;
esdhc_clock_enable(host, false);
return;
}
- /* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */
+ /* Start pre_div at 2 for vendor version < 2.3. */
if (esdhc->vendor_ver < VENDOR_V_23)
pre_div = 2;
+ /* Fix clock value. */
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;
+ esdhc->clk_fixup && host->mmc->ios.timing == MMC_TIMING_LEGACY)
+ clock_fixup = esdhc->clk_fixup->sd_dflt_max_clk;
else if (esdhc->clk_fixup)
- fixup = esdhc->clk_fixup->max_clk[host->mmc->ios.timing];
-
- if (fixup && clock > fixup)
- clock = fixup;
+ clock_fixup = esdhc->clk_fixup->max_clk[host->mmc->ios.timing];
- temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
- temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN |
- ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK);
- sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+ if (clock_fixup == 0 || clock < clock_fixup)
+ clock_fixup = clock;
- while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
+ /* Calculate pre_div and div. */
+ while (host->max_clk / pre_div / 16 > clock_fixup && pre_div < 256)
pre_div *= 2;
- while (host->max_clk / pre_div / div > clock && div < 16)
+ while (host->max_clk / pre_div / div > clock_fixup && div < 16)
div++;
+ esdhc->div_ratio = pre_div * div;
+
+ /* Limit clock division for HS400 200MHz clock for quirk. */
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) {
+ if (esdhc->div_ratio <= 4) {
pre_div = 4;
div = 1;
- } else if (division <= 8) {
+ } else if (esdhc->div_ratio <= 8) {
pre_div = 4;
div = 2;
- } else if (division <= 12) {
+ } else if (esdhc->div_ratio <= 12) {
pre_div = 4;
div = 3;
} else {
pr_warn("%s: using unsupported clock division.\n",
mmc_hostname(host->mmc));
}
+ esdhc->div_ratio = pre_div * div;
}
+ host->mmc->actual_clock = host->max_clk / esdhc->div_ratio;
+
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;
+ clock, host->mmc->actual_clock);
+
+ /* Set clock division into register. */
pre_div >>= 1;
div--;
+ esdhc_clock_enable(host, false);
+
temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
- temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
- | (div << ESDHC_DIVIDER_SHIFT)
- | (pre_div << ESDHC_PREDIV_SHIFT));
+ temp &= ~ESDHC_CLOCK_MASK;
+ temp |= ((div << ESDHC_DIVIDER_SHIFT) |
+ (pre_div << ESDHC_PREDIV_SHIFT));
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+ /*
+ * Wait max 20 ms. If vendor version is 2.2 or lower, do not
+ * wait clock stable bit which does not exist.
+ */
+ timeout = ktime_add_ms(ktime_get(), 20);
+ while (esdhc->vendor_ver > VENDOR_V_22) {
+ bool timedout = ktime_after(ktime_get(), timeout);
+
+ if (sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)
+ break;
+ if (timedout) {
+ pr_err("%s: Internal clock never stabilised.\n",
+ mmc_hostname(host->mmc));
+ break;
+ }
+ usleep_range(10, 20);
+ }
+
+ /* Additional setting for HS400. */
if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 &&
clock == MMC_HS200_MAX_DTR) {
temp = sdhci_readl(host, ESDHC_TBCTL);
@@ -711,25 +745,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
esdhc_clock_enable(host, false);
esdhc_flush_async_fifo(host);
}
-
- /* Wait max 20 ms */
- timeout = ktime_add_ms(ktime_get(), 20);
- while (1) {
- bool timedout = ktime_after(ktime_get(), timeout);
-
- if (sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)
- break;
- if (timedout) {
- pr_err("%s: Internal clock never stabilised.\n",
- mmc_hostname(host->mmc));
- return;
- }
- udelay(10);
- }
-
- temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
- temp |= ESDHC_CLOCK_SDCLKEN;
- sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+ esdhc_clock_enable(host, false);
}
static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
--
2.7.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [v2, 1/2] mmc: sdhci-of-esdhc: fix esdhc_reset() for different controller versions
2020-01-08 4:07 [v2, 1/2] mmc: sdhci-of-esdhc: fix esdhc_reset() for different controller versions Yangbo Lu
2020-01-08 4:07 ` [v2, 2/2] mmc: sdhci-of-esdhc: fix clock setting " Yangbo Lu
@ 2020-01-16 14:39 ` Ulf Hansson
1 sibling, 0 replies; 4+ messages in thread
From: Ulf Hansson @ 2020-01-16 14:39 UTC (permalink / raw)
To: Yangbo Lu; +Cc: linux-mmc, Adrian Hunter
On Wed, 8 Jan 2020 at 05:08, Yangbo Lu <yangbo.lu@nxp.com> wrote:
>
> This patch is to fix operating in esdhc_reset() for different
> controller versions, and to add bus-width restoring after data
> reset for eSDHC (verdor version <= 2.2).
>
> Also add annotation for understanding.
>
> Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
> Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Applied for next, thanks!
Kind regards
Uffe
> ---
> Changes for v2:
> - Added ACK from Adrian.
> - Used preferred style for comments.
> ---
> drivers/mmc/host/sdhci-of-esdhc.c | 43 +++++++++++++++++++++++++++++++++++----
> 1 file changed, 39 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
> index cd3b676..1110f90 100644
> --- a/drivers/mmc/host/sdhci-of-esdhc.c
> +++ b/drivers/mmc/host/sdhci-of-esdhc.c
> @@ -758,23 +758,58 @@ 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;
> + u32 val, bus_width = 0;
>
> + /*
> + * Add delay to make sure all the DMA transfers are finished
> + * for quirk.
> + */
> if (esdhc->quirk_delay_before_data_reset &&
> (mask & SDHCI_RESET_DATA) &&
> (host->flags & SDHCI_REQ_USE_DMA))
> mdelay(5);
>
> + /*
> + * Save bus-width for eSDHC whose vendor version is 2.2
> + * or lower for data reset.
> + */
> + if ((mask & SDHCI_RESET_DATA) &&
> + (esdhc->vendor_ver <= VENDOR_V_22)) {
> + val = sdhci_readl(host, ESDHC_PROCTL);
> + bus_width = val & ESDHC_CTRL_BUSWIDTH_MASK;
> + }
> +
> sdhci_reset(host, mask);
>
> - sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
> - sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
> + /*
> + * Restore bus-width setting and interrupt registers for eSDHC
> + * whose vendor version is 2.2 or lower for data reset.
> + */
> + if ((mask & SDHCI_RESET_DATA) &&
> + (esdhc->vendor_ver <= VENDOR_V_22)) {
> + val = sdhci_readl(host, ESDHC_PROCTL);
> + val &= ~ESDHC_CTRL_BUSWIDTH_MASK;
> + val |= bus_width;
> + sdhci_writel(host, val, ESDHC_PROCTL);
> +
> + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
> + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
> + }
>
> - if (mask & SDHCI_RESET_ALL) {
> + /*
> + * Some bits have to be cleaned manually for eSDHC whose spec
> + * version is higher than 3.0 for all reset.
> + */
> + if ((mask & SDHCI_RESET_ALL) &&
> + (esdhc->spec_ver >= SDHCI_SPEC_300)) {
> val = sdhci_readl(host, ESDHC_TBCTL);
> val &= ~ESDHC_TB_EN;
> sdhci_writel(host, val, ESDHC_TBCTL);
>
> + /*
> + * Initialize eSDHC_DLLCFG1[DLL_PD_PULSE_STRETCH_SEL] to
> + * 0 for quirk.
> + */
> if (esdhc->quirk_unreliable_pulse_detection) {
> val = sdhci_readl(host, ESDHC_DLLCFG1);
> val &= ~ESDHC_DLL_PD_PULSE_STRETCH_SEL;
> --
> 2.7.4
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [v2, 2/2] mmc: sdhci-of-esdhc: fix clock setting for different controller versions
2020-01-08 4:07 ` [v2, 2/2] mmc: sdhci-of-esdhc: fix clock setting " Yangbo Lu
@ 2020-01-16 14:39 ` Ulf Hansson
0 siblings, 0 replies; 4+ messages in thread
From: Ulf Hansson @ 2020-01-16 14:39 UTC (permalink / raw)
To: Yangbo Lu; +Cc: linux-mmc, Adrian Hunter
On Wed, 8 Jan 2020 at 05:08, Yangbo Lu <yangbo.lu@nxp.com> wrote:
>
> This patch is to fix clock setting code for different controller
> versions. Two of HW changes after vendor version 2.2 are removing
> PEREN/HCKEN/IPGEN bits in system control register, and adding SD
> clock stable bit in present state register. This patch cleans up
> related code too.
>
> Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
Applied for next, thanks!
Kind regards
Uffe
> ---
> Changes for v2:
> - Used preferred style for comments.
> ---
> drivers/mmc/host/sdhci-of-esdhc.c | 128 +++++++++++++++++++++-----------------
> 1 file changed, 72 insertions(+), 56 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
> index 1110f90..6a58cf9 100644
> --- a/drivers/mmc/host/sdhci-of-esdhc.c
> +++ b/drivers/mmc/host/sdhci-of-esdhc.c
> @@ -562,32 +562,46 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
>
> static void esdhc_clock_enable(struct sdhci_host *host, bool enable)
> {
> - u32 val;
> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
> ktime_t timeout;
> + u32 val, clk_en;
> +
> + clk_en = ESDHC_CLOCK_SDCLKEN;
> +
> + /*
> + * IPGEN/HCKEN/PEREN bits exist on eSDHC whose vendor version
> + * is 2.2 or lower.
> + */
> + if (esdhc->vendor_ver <= VENDOR_V_22)
> + clk_en |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN |
> + ESDHC_CLOCK_PEREN);
>
> val = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
>
> if (enable)
> - val |= ESDHC_CLOCK_SDCLKEN;
> + val |= clk_en;
> else
> - val &= ~ESDHC_CLOCK_SDCLKEN;
> + val &= ~clk_en;
>
> sdhci_writel(host, val, ESDHC_SYSTEM_CONTROL);
>
> - /* Wait max 20 ms */
> + /*
> + * Wait max 20 ms. If vendor version is 2.2 or lower, do not
> + * wait clock stable bit which does not exist.
> + */
> timeout = ktime_add_ms(ktime_get(), 20);
> - val = ESDHC_CLOCK_STABLE;
> - while (1) {
> + while (esdhc->vendor_ver > VENDOR_V_22) {
> bool timedout = ktime_after(ktime_get(), timeout);
>
> - if (sdhci_readl(host, ESDHC_PRSSTAT) & val)
> + if (sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)
> break;
> if (timedout) {
> pr_err("%s: Internal clock never stabilised.\n",
> mmc_hostname(host->mmc));
> break;
> }
> - udelay(10);
> + usleep_range(10, 20);
> }
> }
>
> @@ -621,77 +635,97 @@ 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;
> + unsigned int pre_div = 1, div = 1;
> + unsigned int clock_fixup = 0;
> ktime_t timeout;
> - long fixup = 0;
> u32 temp;
>
> - host->mmc->actual_clock = 0;
> -
> if (clock == 0) {
> + host->mmc->actual_clock = 0;
> esdhc_clock_enable(host, false);
> return;
> }
>
> - /* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */
> + /* Start pre_div at 2 for vendor version < 2.3. */
> if (esdhc->vendor_ver < VENDOR_V_23)
> pre_div = 2;
>
> + /* Fix clock value. */
> 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;
> + esdhc->clk_fixup && host->mmc->ios.timing == MMC_TIMING_LEGACY)
> + clock_fixup = esdhc->clk_fixup->sd_dflt_max_clk;
> else if (esdhc->clk_fixup)
> - fixup = esdhc->clk_fixup->max_clk[host->mmc->ios.timing];
> -
> - if (fixup && clock > fixup)
> - clock = fixup;
> + clock_fixup = esdhc->clk_fixup->max_clk[host->mmc->ios.timing];
>
> - temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
> - temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN |
> - ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK);
> - sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
> + if (clock_fixup == 0 || clock < clock_fixup)
> + clock_fixup = clock;
>
> - while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
> + /* Calculate pre_div and div. */
> + while (host->max_clk / pre_div / 16 > clock_fixup && pre_div < 256)
> pre_div *= 2;
>
> - while (host->max_clk / pre_div / div > clock && div < 16)
> + while (host->max_clk / pre_div / div > clock_fixup && div < 16)
> div++;
>
> + esdhc->div_ratio = pre_div * div;
> +
> + /* Limit clock division for HS400 200MHz clock for quirk. */
> 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) {
> + if (esdhc->div_ratio <= 4) {
> pre_div = 4;
> div = 1;
> - } else if (division <= 8) {
> + } else if (esdhc->div_ratio <= 8) {
> pre_div = 4;
> div = 2;
> - } else if (division <= 12) {
> + } else if (esdhc->div_ratio <= 12) {
> pre_div = 4;
> div = 3;
> } else {
> pr_warn("%s: using unsupported clock division.\n",
> mmc_hostname(host->mmc));
> }
> + esdhc->div_ratio = pre_div * div;
> }
>
> + host->mmc->actual_clock = host->max_clk / esdhc->div_ratio;
> +
> 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;
> + clock, host->mmc->actual_clock);
> +
> + /* Set clock division into register. */
> pre_div >>= 1;
> div--;
>
> + esdhc_clock_enable(host, false);
> +
> temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
> - temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
> - | (div << ESDHC_DIVIDER_SHIFT)
> - | (pre_div << ESDHC_PREDIV_SHIFT));
> + temp &= ~ESDHC_CLOCK_MASK;
> + temp |= ((div << ESDHC_DIVIDER_SHIFT) |
> + (pre_div << ESDHC_PREDIV_SHIFT));
> sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
>
> + /*
> + * Wait max 20 ms. If vendor version is 2.2 or lower, do not
> + * wait clock stable bit which does not exist.
> + */
> + timeout = ktime_add_ms(ktime_get(), 20);
> + while (esdhc->vendor_ver > VENDOR_V_22) {
> + bool timedout = ktime_after(ktime_get(), timeout);
> +
> + if (sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)
> + break;
> + if (timedout) {
> + pr_err("%s: Internal clock never stabilised.\n",
> + mmc_hostname(host->mmc));
> + break;
> + }
> + usleep_range(10, 20);
> + }
> +
> + /* Additional setting for HS400. */
> if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 &&
> clock == MMC_HS200_MAX_DTR) {
> temp = sdhci_readl(host, ESDHC_TBCTL);
> @@ -711,25 +745,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
> esdhc_clock_enable(host, false);
> esdhc_flush_async_fifo(host);
> }
> -
> - /* Wait max 20 ms */
> - timeout = ktime_add_ms(ktime_get(), 20);
> - while (1) {
> - bool timedout = ktime_after(ktime_get(), timeout);
> -
> - if (sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)
> - break;
> - if (timedout) {
> - pr_err("%s: Internal clock never stabilised.\n",
> - mmc_hostname(host->mmc));
> - return;
> - }
> - udelay(10);
> - }
> -
> - temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
> - temp |= ESDHC_CLOCK_SDCLKEN;
> - sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
> + esdhc_clock_enable(host, false);
> }
>
> static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
> --
> 2.7.4
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2020-01-16 14:40 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-08 4:07 [v2, 1/2] mmc: sdhci-of-esdhc: fix esdhc_reset() for different controller versions Yangbo Lu
2020-01-08 4:07 ` [v2, 2/2] mmc: sdhci-of-esdhc: fix clock setting " Yangbo Lu
2020-01-16 14:39 ` Ulf Hansson
2020-01-16 14:39 ` [v2, 1/2] mmc: sdhci-of-esdhc: fix esdhc_reset() " Ulf Hansson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).