linux-mmc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Ulf Hansson <ulf.hansson@linaro.org>
To: Yangbo Lu <yangbo.lu@nxp.com>
Cc: "linux-mmc@vger.kernel.org" <linux-mmc@vger.kernel.org>,
	Adrian Hunter <adrian.hunter@intel.com>
Subject: Re: [v2, 2/2] mmc: sdhci-of-esdhc: fix clock setting for different controller versions
Date: Thu, 16 Jan 2020 15:39:38 +0100	[thread overview]
Message-ID: <CAPDyKFqDGv2LJ7eDJYtoP5vgc_EuM_cqawEU5GUW_pJzAOyi=A@mail.gmail.com> (raw)
In-Reply-To: <20200108040713.38888-2-yangbo.lu@nxp.com>

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
>

  reply	other threads:[~2020-01-16 14:40 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
2020-01-16 14:39 ` [v2, 1/2] mmc: sdhci-of-esdhc: fix esdhc_reset() " Ulf Hansson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAPDyKFqDGv2LJ7eDJYtoP5vgc_EuM_cqawEU5GUW_pJzAOyi=A@mail.gmail.com' \
    --to=ulf.hansson@linaro.org \
    --cc=adrian.hunter@intel.com \
    --cc=linux-mmc@vger.kernel.org \
    --cc=yangbo.lu@nxp.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).