diff options
author | Jerome Brunet <jbrunet@baylibre.com> | 2017-08-28 16:29:08 +0200 |
---|---|---|
committer | Ulf Hansson <ulf.hansson@linaro.org> | 2017-08-30 15:03:48 +0200 |
commit | 844c8a75f476696e5e472d904d155d5f583f915d (patch) | |
tree | 4d837a2046f632b341d63f6d1c639ba636fef74a /drivers/mmc/host | |
parent | mmc: meson-gx: rework clock init function (diff) | |
download | linux-844c8a75f476696e5e472d904d155d5f583f915d.tar.xz linux-844c8a75f476696e5e472d904d155d5f583f915d.zip |
mmc: meson-gx: fix dual data rate mode frequencies
In DDR modes, meson mmc controller requires an input rate twice as fast
as the output rate
Fixes: 51c5d8447bd7 ("MMC: meson: initial support for GX platforms")
Reviewed-by: Kevin Hilman <khilman@baylibre.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r-- | drivers/mmc/host/meson-gx-mmc.c | 41 |
1 files changed, 29 insertions, 12 deletions
diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 7800a7ace2de..341e5a1b32cc 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -262,14 +262,29 @@ static void meson_mmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, mmc_get_dma_dir(data)); } -static int meson_mmc_clk_set(struct meson_host *host, unsigned long clk_rate) +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; +} + +static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios) { 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 == clk_rate) + if (host->req_rate == rate) return 0; /* stop clock */ @@ -278,25 +293,29 @@ static int meson_mmc_clk_set(struct meson_host *host, unsigned long clk_rate) writel(cfg, host->regs + SD_EMMC_CFG); host->req_rate = 0; - if (!clk_rate) { + if (!rate) { mmc->actual_clock = 0; /* return with clock being stopped */ return 0; } - ret = clk_set_rate(host->mmc_clk, clk_rate); + 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", - clk_rate, ret); + rate, ret); return ret; } - host->req_rate = clk_rate; + host->req_rate = rate; 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)) + mmc->actual_clock >>= 1; + dev_dbg(host->dev, "clk rate: %u Hz\n", mmc->actual_clock); - if (clk_rate != mmc->actual_clock) - dev_dbg(host->dev, "requested rate was %lu\n", clk_rate); + if (ios->clock != mmc->actual_clock) + dev_dbg(host->dev, "requested rate was %u\n", ios->clock); /* (re)start clock */ cfg = readl(host->regs + SD_EMMC_CFG); @@ -490,16 +509,14 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) val |= FIELD_PREP(CFG_BUS_WIDTH_MASK, bus_width); val &= ~CFG_DDR; - if (ios->timing == MMC_TIMING_UHS_DDR50 || - ios->timing == MMC_TIMING_MMC_DDR52 || - ios->timing == MMC_TIMING_MMC_HS400) + if (meson_mmc_timing_is_ddr(ios)) val |= CFG_DDR; val &= ~CFG_CHK_DS; if (ios->timing == MMC_TIMING_MMC_HS400) val |= CFG_CHK_DS; - err = meson_mmc_clk_set(host, ios->clock); + err = meson_mmc_clk_set(host, ios); if (err) dev_err(host->dev, "Failed to set clock: %d\n,", err); |