From ea0f7662531fd360abf300691c85ceff5a0d0397 Mon Sep 17 00:00:00 2001 From: John Keeping Date: Tue, 17 Jan 2023 17:07:47 +0000 Subject: mmc: rockchip_dw_mmc: fix DDR52 8-bit mode handling The RK3288 TRM states that, for 8-bit DDR modes: The CLKDIV register should always be programmed with a value higher than zero (0); that is, a clock divider should always be used for 8-bit DDR mode. In Linux, the driver applies this logic for all SoCs using the driver and does not distinguish RK3288, so presumably this requirement is the same for all other Rockchip SoCs using this IP. Add the necessary code to double the clock frequency when 8-bit DDR is selected. The dw_mmc core already handles setting CLKDIV correctly given the input clock and desired bus clock. Signed-off-by: John Keeping Reviewed-by: Jaehoon Chung --- drivers/mmc/rockchip_dw_mmc.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index 573bf16c875..3661ce33143 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -41,6 +41,14 @@ static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq) struct rockchip_dwmmc_priv *priv = dev_get_priv(dev); int ret; + /* + * The clock frequency chosen here affects CLKDIV in the dw_mmc core. + * That can be either 0 or 1, but it must be set to 1 for eMMC DDR52 + * 8-bit mode. It will be set to 0 for all other modes. + */ + if (host->mmc->selected_mode == MMC_DDR_52 && host->mmc->bus_width == 8) + freq *= 2; + ret = clk_set_rate(&priv->clk, freq); if (ret < 0) { debug("%s: err=%d\n", __func__, ret); -- cgit v1.3.1 From 6ddffa89cb8396bf043adcc5090e8b1a9b1d0246 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 27 Feb 2023 23:49:27 +0100 Subject: mmc: renesas-sdhi: Always configure default SDnH clock rate to 800 MHz The prior stage bootloader might have left the SDnCKCR register in completely arbitrary state before passing control to U-Boot, which includes the register being populated with incorrect values. Currently the SDHI driver will attempt to use clock framework to configure SDn clock, which may fail in case SDnCKCR contains invalid values for the SDnH clock, because the clock framework would not be able to determine SDnH clock rate and would get -EINVAL instead, which in turn would not allow the clock framework to determine the correct SDn clock divider ratio. This failure occurs specifically in case SDnCKCR reads back 0x209 . Correct the problem by first setting default SDnH clock rate to 800 MHz, thus assuring the SDnCKCR SDnH bits are correct, and only afterward set up the SDn clock rate to default 200 MHz. Note that the SDHI driver may reconfigure SDnH clock later based on IOS settings obtained from the attached card, the 800 MHz set up here is only the default value. Signed-off-by: Marek Vasut --- drivers/mmc/renesas-sdhi.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 4a1accebfcb..2473261f3c4 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -977,8 +977,16 @@ static int renesas_sdhi_probe(struct udevice *dev) /* optional SDnH clock */ ret = clk_get_by_name(dev, "clkh", &priv->clkh); - if (ret < 0) + if (ret < 0) { dev_dbg(dev, "failed to get clkh\n"); + } else { + ret = clk_set_rate(&priv->clkh, 800000000); + if (ret < 0) { + dev_err(dev, "failed to set rate for SDnH clock\n"); + clk_free(&priv->clk); + return ret; + } + } /* set to max rate */ ret = clk_set_rate(&priv->clk, 200000000); -- cgit v1.3.1 From f20a61af4209785721bdee96131785d9dc24698d Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 27 Feb 2023 23:49:28 +0100 Subject: mmc: renesas-sdhi: Add proper probe error fail path In case one of the calls in probe fail, trigger a fail path and undo all the steps done in probe until the point of failure. The current implementation failed to stop controller clock and free claimed clock, so fix that. Furthermore, print return code in error prints for easier debugging. Signed-off-by: Marek Vasut --- drivers/mmc/renesas-sdhi.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 2473261f3c4..34119f949aa 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -982,37 +982,45 @@ static int renesas_sdhi_probe(struct udevice *dev) } else { ret = clk_set_rate(&priv->clkh, 800000000); if (ret < 0) { - dev_err(dev, "failed to set rate for SDnH clock\n"); - clk_free(&priv->clk); - return ret; + dev_err(dev, "failed to set rate for SDnH clock (%d)\n", ret); + goto err_clk; } } /* set to max rate */ ret = clk_set_rate(&priv->clk, 200000000); if (ret < 0) { - dev_err(dev, "failed to set rate for host clock\n"); - clk_free(&priv->clk); - return ret; + dev_err(dev, "failed to set rate for SDn clock (%d)\n", ret); + goto err_clkh; } ret = clk_enable(&priv->clk); if (ret) { - dev_err(dev, "failed to enable host clock\n"); - return ret; + dev_err(dev, "failed to enable SDn clock (%d)\n", ret); + goto err_clkh; } priv->quirks = quirks; ret = tmio_sd_probe(dev, quirks); + if (ret) + goto err_tmio_probe; renesas_sdhi_filter_caps(dev); #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) - if (!ret && (priv->caps & TMIO_SD_CAP_RCAR_UHS)) + if (priv->caps & TMIO_SD_CAP_RCAR_UHS) renesas_sdhi_reset_tuning(priv); #endif + return 0; + +err_tmio_probe: + clk_disable(&priv->clk); +err_clkh: + clk_free(&priv->clkh); +err_clk: + clk_free(&priv->clk); return ret; } -- cgit v1.3.1