From: Jerome Brunet <jbrunet@baylibre.com>
To: Ulf Hansson <ulf.hansson@linaro.org>,
Kevin Hilman <khilman@baylibre.com>
Cc: linux-amlogic@lists.infradead.org, linux-mmc@vger.kernel.org,
linux-kernel@vger.kernel.org,
Jerome Brunet <jbrunet@baylibre.com>
Subject: [PATCH 5/7] mmc: meson-gx: avoid clock glitch when switching to DDR modes
Date: Wed, 17 Apr 2019 22:43:53 +0200 [thread overview]
Message-ID: <20190417204355.469-6-jbrunet@baylibre.com> (raw)
In-Reply-To: <20190417204355.469-1-jbrunet@baylibre.com>
Activating DDR in the Amlogic mmc controller, among other things, will
divide the output clock by 2. So by activating it with clock on, we are
creating a glitch on the output.
Instead, let's deal with DDR when the clock output is off, when setting
the clock.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/mmc/host/meson-gx-mmc.c | 72 +++++++++++++++++++--------------
1 file changed, 42 insertions(+), 30 deletions(-)
diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c
index 118f09da8dfb..f77b9327a590 100644
--- a/drivers/mmc/host/meson-gx-mmc.c
+++ b/drivers/mmc/host/meson-gx-mmc.c
@@ -169,6 +169,7 @@ struct meson_host {
struct clk *rx_clk;
struct clk *tx_clk;
unsigned long req_rate;
+ bool ddr;
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
@@ -384,16 +385,6 @@ static void meson_mmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
mmc_get_dma_dir(data));
}
-static bool meson_mmc_timing_is_ddr(struct mmc_ios *ios)
-{
- if (ios->timing == MMC_TIMING_MMC_DDR52 ||
- ios->timing == MMC_TIMING_UHS_DDR50 ||
- ios->timing == MMC_TIMING_MMC_HS400)
- return true;
-
- return false;
-}
-
/*
* Gating the clock on this controller is tricky. It seems the mmc clock
* is also used by the controller. It may crash during some operation if the
@@ -430,36 +421,41 @@ static void meson_mmc_clk_ungate(struct meson_host *host)
writel(cfg, host->regs + SD_EMMC_CFG);
}
-static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios)
+static int meson_mmc_clk_set(struct meson_host *host, unsigned long rate,
+ bool ddr)
{
struct mmc_host *mmc = host->mmc;
- unsigned long rate = ios->clock;
int ret;
u32 cfg;
- /* DDR modes require higher module clock */
- if (meson_mmc_timing_is_ddr(ios))
- rate <<= 1;
-
/* Same request - bail-out */
- if (host->req_rate == rate)
+ if (host->ddr == ddr && host->req_rate == rate)
return 0;
/* stop clock */
meson_mmc_clk_gate(host);
host->req_rate = 0;
+ mmc->actual_clock = 0;
- if (!rate) {
- mmc->actual_clock = 0;
- /* return with clock being stopped */
+ /* return with clock being stopped */
+ if (!rate)
return 0;
- }
/* Stop the clock during rate change to avoid glitches */
cfg = readl(host->regs + SD_EMMC_CFG);
cfg |= CFG_STOP_CLOCK;
writel(cfg, host->regs + SD_EMMC_CFG);
+ if (ddr) {
+ /* DDR modes require higher module clock */
+ rate <<= 1;
+ cfg |= CFG_DDR;
+ } else {
+ cfg &= ~CFG_DDR;
+ }
+ writel(cfg, host->regs + SD_EMMC_CFG);
+ host->ddr = ddr;
+
ret = clk_set_rate(host->mmc_clk, rate);
if (ret) {
dev_err(host->dev, "Unable to set cfg_div_clk to %lu. ret=%d\n",
@@ -471,12 +467,14 @@ static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios)
mmc->actual_clock = clk_get_rate(host->mmc_clk);
/* We should report the real output frequency of the controller */
- if (meson_mmc_timing_is_ddr(ios))
+ if (ddr) {
+ host->req_rate >>= 1;
mmc->actual_clock >>= 1;
+ }
dev_dbg(host->dev, "clk rate: %u Hz\n", mmc->actual_clock);
- if (ios->clock != mmc->actual_clock)
- dev_dbg(host->dev, "requested rate was %u\n", ios->clock);
+ if (rate != mmc->actual_clock)
+ dev_dbg(host->dev, "requested rate was %lu\n", rate);
/* (re)start clock */
meson_mmc_clk_ungate(host);
@@ -750,6 +748,25 @@ static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk);
}
+static int meson_mmc_prepare_ios_clock(struct meson_host *host,
+ struct mmc_ios *ios)
+{
+ bool ddr;
+
+ switch (ios->timing) {
+ case MMC_TIMING_MMC_DDR52:
+ case MMC_TIMING_UHS_DDR50:
+ ddr = true;
+ break;
+
+ default:
+ ddr = false;
+ break;
+ }
+
+ return meson_mmc_clk_set(host, ios->clock, ddr);
+}
+
static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct meson_host *host = mmc_priv(mmc);
@@ -819,15 +836,10 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
val &= ~CFG_BUS_WIDTH_MASK;
val |= FIELD_PREP(CFG_BUS_WIDTH_MASK, bus_width);
- val &= ~CFG_DDR;
- if (meson_mmc_timing_is_ddr(ios))
- val |= CFG_DDR;
-
- err = meson_mmc_clk_set(host, ios);
+ err = meson_mmc_prepare_ios_clock(host, ios);
if (err)
dev_err(host->dev, "Failed to set clock: %d\n,", err);
- writel(val, host->regs + SD_EMMC_CFG);
dev_dbg(host->dev, "SD_EMMC_CFG: 0x%08x\n", val);
}
--
2.20.1
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
next prev parent reply other threads:[~2019-04-17 20:44 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-04-17 20:43 [PATCH 0/7] mmc: meson-gx: clean up and tuning update Jerome Brunet
2019-04-17 20:43 ` [PATCH 1/7] mmc: meson-gx: remove open coded read with timeout Jerome Brunet
2019-04-18 20:18 ` Martin Blumenstingl
2019-04-17 20:43 ` [PATCH 2/7] mmc: meson-gx: ack only raised irq Jerome Brunet
2019-04-17 20:43 ` [PATCH 3/7] mmc: meson-gx: irq is not shared Jerome Brunet
2019-04-18 19:52 ` Martin Blumenstingl
2019-04-17 20:43 ` [PATCH 4/7] mmc: meson-gx: disable HS400 Jerome Brunet
2019-04-17 20:43 ` Jerome Brunet [this message]
2019-04-18 20:16 ` [PATCH 5/7] mmc: meson-gx: avoid clock glitch when switching to DDR modes Martin Blumenstingl
2019-04-18 20:46 ` Jerome Brunet
2019-04-18 20:53 ` Martin Blumenstingl
2019-04-18 21:15 ` Jerome Brunet
2019-04-19 8:53 ` Jerome Brunet
2019-04-20 9:23 ` Martin Blumenstingl
2019-04-17 20:43 ` [PATCH 6/7] mmc: meson-gx: remove Rx phase tuning Jerome Brunet
2019-04-17 20:43 ` [PATCH 7/7] mmc: meson-gx: add signal resampling tuning Jerome Brunet
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=20190417204355.469-6-jbrunet@baylibre.com \
--to=jbrunet@baylibre.com \
--cc=khilman@baylibre.com \
--cc=linux-amlogic@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mmc@vger.kernel.org \
--cc=ulf.hansson@linaro.org \
/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
all inboxes | Powered by JetHome®