All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.