Hi Jeahoon,
>On 6/28/21 6:19 PM, Yifeng Zhao wrote: >> This patch adds support for the RK3568 platform to this driver. >> >> Signed-off-by: Yifeng Zhao <yifeng.z...@rock-chips.com> >> --- >> >> Changes in v2: >> - Used sdhci_set_clock api to set clock. >> - Used read_poll_timeout api to check dll status. >> >> drivers/mmc/rockchip_sdhci.c | 117 +++++++++++++++++++++++++++++++++++ >> 1 file changed, 117 insertions(+) >> >> diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c >> index 2973911446..5ac524c9c9 100644 >> --- a/drivers/mmc/rockchip_sdhci.c >> +++ b/drivers/mmc/rockchip_sdhci.c >> @@ -42,6 +42,34 @@ >> ((((x) >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK) ==\ >> PHYCTRL_DLLRDY_DONE) >> >> +/* Rockchip specific Registers */ >> +#define DWCMSHC_EMMC_DLL_CTRL 0x800 >> +#define DWCMSHC_EMMC_DLL_CTRL_RESET BIT(1) >> +#define DWCMSHC_EMMC_DLL_RXCLK 0x804 >> +#define DWCMSHC_EMMC_DLL_TXCLK 0x808 >> +#define DWCMSHC_EMMC_DLL_STRBIN 0x80c >> +#define DWCMSHC_EMMC_DLL_STATUS0 0x840 >> +#define DWCMSHC_EMMC_DLL_STATUS1 0x844 >> +#define DWCMSHC_EMMC_DLL_START BIT(0) >> +#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL 29 >> +#define DWCMSHC_EMMC_DLL_START_POINT 16 >> +#define DWCMSHC_EMMC_DLL_START_DEFAULT 5 >> +#define DWCMSHC_EMMC_DLL_INC_VALUE 2 >> +#define DWCMSHC_EMMC_DLL_INC 8 >> +#define DWCMSHC_EMMC_DLL_DLYENA BIT(27) >> +#define DLL_TXCLK_TAPNUM_DEFAULT 0x10 >> +#define DLL_STRBIN_TAPNUM_DEFAULT 0x3 >> +#define DLL_TXCLK_TAPNUM_FROM_SW BIT(24) >> +#define DWCMSHC_EMMC_DLL_LOCKED BIT(8) >> +#define DWCMSHC_EMMC_DLL_TIMEOUT BIT(9) >> +#define DLL_RXCLK_NO_INVERTER 1 >> +#define DLL_RXCLK_INVERTER 0 >> +#define DWCMSHC_ENHANCED_STROBE BIT(8) >> +#define DLL_LOCK_WO_TMOUT(x) \ >> + ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \ >> + (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0)) >> +#define ROCKCHIP_MAX_CLKS 3 >> + >> struct rockchip_sdhc_plat { >> struct mmc_config cfg; >> struct mmc mmc; >> @@ -178,6 +206,85 @@ static int rk3399_sdhci_emmc_set_clock(struct >> sdhci_host *host, unsigned int clo >> return 0; >> } >> >> +static int rk3568_emmc_phy_init(struct udevice *dev) >> +{ >> + struct rockchip_sdhc *prv = dev_get_priv(dev); >> + struct sdhci_host *host = &prv->host; >> + u32 extra; >> + >> + extra = DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL; >> + sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK); >> + >> + return 0; >> +} >> + >> +static int rk3568_sdhci_emmc_set_clock(struct sdhci_host *host, unsigned >> int clock) >> +{ >> + struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, >> host); >> + int max_clk = host->max_clk; >> + unsigned long mmc_clock; >> + int val, ret; >> + u32 extra; >> + >> + if (clock) { >> + mmc_clock = clk_set_rate(&priv->emmc_clk, clock); > >Not need to use mmc_clock. It's possible to assign to host->max_clk directly. > >host->max_clk = clk_set_rate(); >if (IS_ERR_VALUE(host->max_clk)) > host->max_clk = max_clk; The variable types are different, IS_ERR_VALUE(host->max_clk) will not got the right results. unsigned int max_clk; #define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO) >> + if (IS_ERR_VALUE(mmc_clock)) >> + host->max_clk = max_clk; >> + else >> + host->max_clk = mmc_clock; >> + } >> + >> + sdhci_set_clock(host->mmc, clock); >> + if (!clock) >> + return 0; >> + host->max_clk = max_clk; > >Why reassign with max_clk? The host->max_clk is config by dts and need to reassign. I will recheck the div config in sdhci_set_clock, it maybe work and no need to call clk_set_rate() to chang the source clock?? > >> + >> + if (clock >= 100 * MHz) { >> + /* reset DLL */ >> + sdhci_writel(host, DWCMSHC_EMMC_DLL_CTRL_RESET, >> DWCMSHC_EMMC_DLL_CTRL); >> + udelay(1); >> + sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL); >> + >> + /* Init DLL settings */ >> + extra = DWCMSHC_EMMC_DLL_START_DEFAULT << >> DWCMSHC_EMMC_DLL_START_POINT | >> + DWCMSHC_EMMC_DLL_INC_VALUE << DWCMSHC_EMMC_DLL_INC | >> + DWCMSHC_EMMC_DLL_START; >> + sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CTRL); >> + >> + ret = read_poll_timeout(readl, host->ioaddr + >> DWCMSHC_EMMC_DLL_STATUS0, >> + val, DLL_LOCK_WO_TMOUT(val), 1, 500); >> + if (ret) >> + return ret; >> + >> + extra = DWCMSHC_EMMC_DLL_DLYENA | >> + DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL; >> + sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK); >> + >> + extra = DWCMSHC_EMMC_DLL_DLYENA | >> + DLL_TXCLK_TAPNUM_DEFAULT | >> + DLL_TXCLK_TAPNUM_FROM_SW; >> + sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK); >> + >> + extra = DWCMSHC_EMMC_DLL_DLYENA | >> + DLL_STRBIN_TAPNUM_DEFAULT; >> + sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); >> + } else { >> + /* reset the clock phase when the frequency is lower than >> 100MHz */ >> + sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL); >> + extra = DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL; >> + sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK); >> + sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK); >> + sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN); >> + } >> + >> + return 0; >> +} >> + >> +static int rk3568_emmc_get_phy(struct udevice *dev) >> +{ >> + return 0; >> +} >> + >> static int rockchip_sdhci_set_ios_post(struct sdhci_host *host) >> { >> struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, >>host); >> @@ -336,11 +443,21 @@ static const struct sdhci_data rk3399_data = { >> .emmc_phy_init = rk3399_emmc_phy_init, >> }; >> >> +static const struct sdhci_data rk3568_data = { >> + .emmc_set_clock = rk3568_sdhci_emmc_set_clock, >> + .get_phy = rk3568_emmc_get_phy, >> + .emmc_phy_init = rk3568_emmc_phy_init, >> +}; >> + >> static const struct udevice_id sdhci_ids[] = { >> { >> .compatible = "arasan,sdhci-5.1", >> .data = (ulong)&rk3399_data, >> }, >> + { >> + .compatible = "rockchip,rk3568-dwcmshc", >> + .data = (ulong)&rk3568_data, >> + }, >> { } >> }; >> >> > > > >