summaryrefslogtreecommitdiff
path: root/drivers/mmc/host
diff options
context:
space:
mode:
authorWolfram Sang <wsa+renesas@sang-engineering.com>2021-11-10 22:15:54 +0300
committerGeert Uytterhoeven <geert+renesas@glider.be>2021-11-19 13:32:39 +0300
commitbb6d3fa98a418b071c5f735e75558604f5f4af66 (patch)
tree24b49efbe47f240e566c1c27240ab9ce0847ddd1 /drivers/mmc/host
parent627151b4966fe68029cd14aa5fd81f5f0c67fa26 (diff)
downloadlinux-bb6d3fa98a418b071c5f735e75558604f5f4af66.tar.xz
clk: renesas: rcar-gen3: Switch to new SD clock handling
The old SD handling code was huge and could not handle all the details which showed up on R-Car Gen3 SoCs meanwhile. It is time to switch to another design. Have SDnH a separate clock, use the existing divider clocks and move the errata handling from the clock driver to the SDHI driver where it belongs. This patch removes the old SD handling code and switch to the new one. This updates the SDHI driver at the same time. Because the SDHI driver can only communicate with the clock driver via clk_set_rate(), I don't see an alternative to this flag-day-approach, so we cross subsystems here. The patch sadly looks messy for the CPG lib, but it is basically a huge chunk of code removed and smaller chunks added. It looks much better when you just view the resulting source file. Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Acked-by: Ulf Hansson <ulf.hansson@linaro.org> # For MMC Link: https://lore.kernel.org/r/20211110191610.5664-6-wsa+renesas@sang-engineering.com Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r--drivers/mmc/host/renesas_sdhi.h1
-rw-r--r--drivers/mmc/host/renesas_sdhi_core.c28
2 files changed, 24 insertions, 5 deletions
diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
index cd82420677cc..66d308e73e17 100644
--- a/drivers/mmc/host/renesas_sdhi.h
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -60,6 +60,7 @@ struct tmio_mmc_dma {
struct renesas_sdhi {
struct clk *clk;
+ struct clk *clkh;
struct clk *clk_cd;
struct tmio_mmc_data mmc_data;
struct tmio_mmc_dma dma_priv;
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index a4407f391f66..31e232bcb5e8 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -127,10 +127,12 @@ static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host)
}
static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
- unsigned int new_clock)
+ unsigned int wanted_clock)
{
struct renesas_sdhi *priv = host_to_priv(host);
+ struct clk *ref_clk = priv->clk;
unsigned int freq, diff, best_freq = 0, diff_min = ~0;
+ unsigned int new_clock, clkh_shift = 0;
int i;
/*
@@ -141,6 +143,16 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2) || mmc_doing_tune(host->mmc))
return clk_get_rate(priv->clk);
+ if (priv->clkh) {
+ bool use_4tap = priv->quirks && priv->quirks->hs400_4taps;
+ bool need_slow_clkh = (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) ||
+ (host->mmc->ios.timing == MMC_TIMING_MMC_HS400);
+ clkh_shift = use_4tap && need_slow_clkh ? 1 : 2;
+ ref_clk = priv->clkh;
+ }
+
+ new_clock = wanted_clock << clkh_shift;
+
/*
* We want the bus clock to be as close as possible to, but no
* greater than, new_clock. As we can divide by 1 << i for
@@ -148,11 +160,10 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
* possible, but no greater than, new_clock << i.
*/
for (i = min(9, ilog2(UINT_MAX / new_clock)); i >= 0; i--) {
- freq = clk_round_rate(priv->clk, new_clock << i);
+ freq = clk_round_rate(ref_clk, new_clock << i);
if (freq > (new_clock << i)) {
/* Too fast; look for a slightly slower option */
- freq = clk_round_rate(priv->clk,
- (new_clock << i) / 4 * 3);
+ freq = clk_round_rate(ref_clk, (new_clock << i) / 4 * 3);
if (freq > (new_clock << i))
continue;
}
@@ -164,7 +175,10 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
}
}
- clk_set_rate(priv->clk, best_freq);
+ clk_set_rate(ref_clk, best_freq);
+
+ if (priv->clkh)
+ clk_set_rate(priv->clk, best_freq >> clkh_shift);
return clk_get_rate(priv->clk);
}
@@ -947,6 +961,10 @@ int renesas_sdhi_probe(struct platform_device *pdev,
mmc_data->max_segs = of_data->max_segs;
dma_priv->dma_buswidth = of_data->dma_buswidth;
host->bus_shift = of_data->bus_shift;
+ /* Fallback for old DTs */
+ if (of_data->sdhi_flags & SDHI_FLAG_NEED_CLKH_FALLBACK)
+ priv->clkh = clk_get_parent(clk_get_parent(priv->clk));
+
}
host->write16_hook = renesas_sdhi_write16_hook;