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
>
next prev parent 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).