clk: renesas: 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.
Based on Linux series by Wolfram Sang, commit bb6d3fa98a41 ("clk:
renesas: rcar-gen3: Switch to new SD clock handling") and commit
e5f7e81ee430a ("mmc: renesas_sdhi: Parse DT for SDnH")
Signed-off-by: Hai Pham <hai.pham.ud@renesas.com>
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
Marek: - Add rcar_clk_* prefix to all functions
- Fix missing ~ in GENMASK(a, b), use clrsetbits_le32 instead
- Use DIV_ROUND_CLOSEST, else if parent clock = 199999992 and
rate = 200000000, the divider would be 0 and table lookup
would fail.
- Turn rcar_clk_get_table_val into signed integer, so it can
return 0 as a valid value and negative values as errors.
- Make the code operate on correct clock and add comment
which explains the reasoning behind it.
- Rebase on changes to
clk: renesas: Introduce and use rcar_clk_get_rate64_div_table function
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c
index f30d784..4a1acce 100644
--- a/drivers/mmc/renesas-sdhi.c
+++ b/drivers/mmc/renesas-sdhi.c
@@ -358,13 +358,21 @@
struct mmc *mmc = mmc_get_mmc_dev(dev);
bool hs400 = (mmc->selected_mode == MMC_HS_400);
int ret, taps = hs400 ? priv->nrtaps : 8;
+ const u32 sdn_rate = 200000000;
+ u32 sdnh_rate = 800000000;
unsigned long new_tap;
u32 reg;
- if (taps == 4) /* HS400 on 4tap SoC needs different clock */
- ret = clk_set_rate(&priv->clk, 400000000);
- else
- ret = clk_set_rate(&priv->clk, 200000000);
+ if (clk_valid(&priv->clkh) && !priv->needs_clkh_fallback) {
+ /* HS400 on 4tap SoC => SDnH=400 MHz, SDn=200 MHz */
+ if (taps == 4)
+ sdnh_rate /= 2;
+ ret = clk_set_rate(&priv->clkh, sdnh_rate);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = clk_set_rate(&priv->clk, sdn_rate);
if (ret < 0)
return ret;
@@ -967,6 +975,11 @@
return ret;
}
+ /* optional SDnH clock */
+ ret = clk_get_by_name(dev, "clkh", &priv->clkh);
+ if (ret < 0)
+ dev_dbg(dev, "failed to get clkh\n");
+
/* set to max rate */
ret = clk_set_rate(&priv->clk, 200000000);
if (ret < 0) {
diff --git a/drivers/mmc/tmio-common.h b/drivers/mmc/tmio-common.h
index e517ed9..88244e8 100644
--- a/drivers/mmc/tmio-common.h
+++ b/drivers/mmc/tmio-common.h
@@ -138,6 +138,7 @@
#endif
#if CONFIG_IS_ENABLED(CLK)
struct clk clk;
+ struct clk clkh;
#endif
#if CONFIG_IS_ENABLED(RENESAS_SDHI)
unsigned int smpcmp;