Re: [PATCH v3 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399
Hi Jack, On Fri, 29 Oct 2021 at 09:45, Jack Mitchell wrote: > > Hi, > > > snip > > > + > > +static int rk3399_emmc_get_phy(struct udevice *dev) > > +{ > > + struct rockchip_sdhc *priv = dev_get_priv(dev); > > + ofnode phy_node; > > + void *grf_base; > > + u32 grf_phy_offset, phandle; > > + > > + phandle = dev_read_u32_default(dev, "phys", 0); > > + phy_node = ofnode_get_by_phandle(phandle); > > + if (!ofnode_valid(phy_node)) { > > + debug("Not found emmc phy device\n"); > > + return -ENODEV; > > + } > > I've just upgraded u-boot on my 3399 board and the emmc is failing to > initialise as it can't find this "phys" node. It's a standard board > setup with the following in the DT. > > { > bus-width = <8>; > mmc-hs400-1_8v; > mmc-hs400-enhanced-strobe; > non-removable; > status = "okay"; > }; > > _phy { > status = "okay"; > }; > > and a vanilla rk3399.dtsi from 2021.10. Do you have any idea why this > might be failing? > > U-Boot SPL 2021.10-00075-g8db2642c55-dirty (Oct 29 2021 - 16:42:46 +0100) > Not found emmc phy device > Trying to boot from MMC1 > > Has anyone booted a 3399 board sucessfully since these patches went in? Yes, chromebook_bob works OK for me. Regards, Simon
Re: [PATCH v3 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399
Hi, > snip > + > +static int rk3399_emmc_get_phy(struct udevice *dev) > +{ > + struct rockchip_sdhc *priv = dev_get_priv(dev); > + ofnode phy_node; > + void *grf_base; > + u32 grf_phy_offset, phandle; > + > + phandle = dev_read_u32_default(dev, "phys", 0); > + phy_node = ofnode_get_by_phandle(phandle); > + if (!ofnode_valid(phy_node)) { > + debug("Not found emmc phy device\n"); > + return -ENODEV; > + } I've just upgraded u-boot on my 3399 board and the emmc is failing to initialise as it can't find this "phys" node. It's a standard board setup with the following in the DT. { bus-width = <8>; mmc-hs400-1_8v; mmc-hs400-enhanced-strobe; non-removable; status = "okay"; }; _phy { status = "okay"; }; and a vanilla rk3399.dtsi from 2021.10. Do you have any idea why this might be failing? U-Boot SPL 2021.10-00075-g8db2642c55-dirty (Oct 29 2021 - 16:42:46 +0100) Not found emmc phy device Trying to boot from MMC1 Has anyone booted a 3399 board sucessfully since these patches went in? Regards, Jack. > + > + grf_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); > + if (grf_base < 0) { > + printf("%s Get syscon grf failed", __func__); > + return -ENODEV; > + } > + grf_phy_offset = ofnode_read_u32_default(phy_node, "reg", 0); > + > + priv->phy = (struct rockchip_emmc_phy *)(grf_base + grf_phy_offset); > + > + return 0; > +} > + > +static int rk3399_sdhci_emmc_set_clock(struct sdhci_host *host, unsigned int > clock) > +{ > + struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, > host); > + int cycle_phy = host->clock != clock && clock > EMMC_MIN_FREQ; > + > + if (cycle_phy) > + rk3399_emmc_phy_power_off(priv->phy); > + > + sdhci_set_clock(host->mmc, clock); > + > + if (cycle_phy) > + rk3399_emmc_phy_power_on(priv->phy, clock); > + > + return 0; > +} > + > +static int rockchip_sdhci_set_ios_post(struct sdhci_host *host) > +{ > + struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, > host); > + struct sdhci_data *data = (struct sdhci_data > *)dev_get_driver_data(priv->dev); > + struct mmc *mmc = host->mmc; > + uint clock = mmc->tran_speed; > + u32 reg; > + > + if (!clock) > + clock = mmc->clock; > + > + if (data->emmc_set_clock) > + data->emmc_set_clock(host, clock); > + > + if (mmc->selected_mode == MMC_HS_400 || mmc->selected_mode == > MMC_HS_400_ES) { > + reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); > + reg &= ~SDHCI_CTRL_UHS_MASK; > + reg |= SDHCI_CTRL_HS400; > + sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); > + } else { > + sdhci_set_uhs_timing(host); > + } > + > + return 0; > +} > + > +static int rockchip_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) > +{ > + struct sdhci_host *host = dev_get_priv(mmc->dev); > + char tuning_loop_counter = SDHCI_TUNING_LOOP_COUNT; > + struct mmc_cmd cmd; > + u32 ctrl, blk_size; > + int ret = 0; > + > + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); > + ctrl |= SDHCI_CTRL_EXEC_TUNING; > + sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); > + > + sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE); > + sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE); > + > + blk_size = SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, 64); > + if (opcode == MMC_CMD_SEND_TUNING_BLOCK_HS200 && host->mmc->bus_width > == 8) > + blk_size = SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, 128); > + sdhci_writew(host, blk_size, SDHCI_BLOCK_SIZE); > + sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); > + > + cmd.cmdidx = opcode; > + cmd.resp_type = MMC_RSP_R1; > + cmd.cmdarg = 0; > + > + do { > + if (tuning_loop_counter-- == 0) > + break; > + > + mmc_send_cmd(mmc, , NULL); > + > + if (opcode == MMC_CMD_SEND_TUNING_BLOCK) > + /* > + * For tuning command, do not do busy loop. As tuning > + * is happening (CLK-DATA latching for setup/hold time > + * requirements), give time to complete > + */ > + udelay(1); > + > + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); > + } while (ctrl & SDHCI_CTRL_EXEC_TUNING); > + > + if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) { > + printf("%s:Tuning failed\n", __func__); > + ret = -EIO; > + } > + > + if (tuning_loop_counter < 0) { > + ctrl &= ~SDHCI_CTRL_TUNED_CLK; > + sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL2); > + } > + > + /* Enable only interrupts served by the SD controller */ > + sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK,
Re: [PATCH v3 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399
Yifeng Zhao 于2021年6月29日周二 下午7:40写道: > > Add clock, phy and other configuration, it is convenient to support > new controller. Here a short summary of the changes: > - Add mmc_of_parse to parse dts config. > - Remove OF_PLATDATA related code. > - Reorder header inclusion. > - Add phy ops. > - add ops set_ios_post to modify the parameters of phy when the > clock changes. > - Add execute tuning api for hs200 tuning. > > Signed-off-by: Yifeng Zhao Reviewed-by: Kever Yang Thanks, - Kever > --- > > Changes in v3: > - Optimize hs200 tuning function. > - Add check for callback function. > - Add return value for tuning function. > - Fixed source clock rate with host->max_clk, the interface clock is divided > from the source clock. > > Changes in v2: > - Add mmc_of_parse to parse dts config. > - Used read_poll_timeout api to check dll lock status > - Add execute tuning api for hs200 tuning > > drivers/mmc/rockchip_sdhci.c | 313 +++ > 1 file changed, 277 insertions(+), 36 deletions(-) > > diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c > index d95f8b2a15..eff134c8f5 100644 > --- a/drivers/mmc/rockchip_sdhci.c > +++ b/drivers/mmc/rockchip_sdhci.c > @@ -6,90 +6,322 @@ > */ > > #include > +#include > #include > +#include > #include > +#include > #include > #include > +#include > #include > #include > +#include "mmc_private.h" > #include > -#include > +#include > +#include > +#include > > /* 400KHz is max freq for card ID etc. Use that as min */ > #define EMMC_MIN_FREQ 40 > +#define KHz(1000) > +#define MHz(1000 * KHz) > +#define SDHCI_TUNING_LOOP_COUNT40 > + > +#define PHYCTRL_CALDONE_MASK 0x1 > +#define PHYCTRL_CALDONE_SHIFT 0x6 > +#define PHYCTRL_CALDONE_DONE 0x1 > +#define PHYCTRL_DLLRDY_MASK0x1 > +#define PHYCTRL_DLLRDY_SHIFT 0x5 > +#define PHYCTRL_DLLRDY_DONE0x1 > +#define PHYCTRL_FREQSEL_200M 0x0 > +#define PHYCTRL_FREQSEL_50M0x1 > +#define PHYCTRL_FREQSEL_100M 0x2 > +#define PHYCTRL_FREQSEL_150M 0x3 > +#define PHYCTRL_DLL_LOCK_WO_TMOUT(x) \ > + x) >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK) ==\ > + PHYCTRL_DLLRDY_DONE) > > struct rockchip_sdhc_plat { > -#if CONFIG_IS_ENABLED(OF_PLATDATA) > - struct dtd_rockchip_rk3399_sdhci_5_1 dtplat; > -#endif > struct mmc_config cfg; > struct mmc mmc; > }; > > +struct rockchip_emmc_phy { > + u32 emmcphy_con[7]; > + u32 reserved; > + u32 emmcphy_status; > +}; > + > struct rockchip_sdhc { > struct sdhci_host host; > + struct udevice *dev; > void *base; > + struct rockchip_emmc_phy *phy; > + struct clk emmc_clk; > +}; > + > +struct sdhci_data { > + int (*emmc_set_clock)(struct sdhci_host *host, unsigned int clock); > + int (*emmc_phy_init)(struct udevice *dev); > + int (*get_phy)(struct udevice *dev); > +}; > + > +static int rk3399_emmc_phy_init(struct udevice *dev) > +{ > + return 0; > +} > + > +static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 > clock) > +{ > + u32 caldone, dllrdy, freqsel; > + > + writel(RK_CLRSETBITS(7 << 4, 0), >emmcphy_con[6]); > + writel(RK_CLRSETBITS(1 << 11, 1 << 11), >emmcphy_con[0]); > + writel(RK_CLRSETBITS(0xf << 7, 6 << 7), >emmcphy_con[0]); > + > + /* > +* According to the user manual, calpad calibration > +* cycle takes more than 2us without the minimal recommended > +* value, so we may need a little margin here > +*/ > + udelay(3); > + writel(RK_CLRSETBITS(1, 1), >emmcphy_con[6]); > + > + /* > +* According to the user manual, it asks driver to > +* wait 5us for calpad busy trimming. But it seems that > +* 5us of caldone isn't enough for all cases. > +*/ > + udelay(500); > + caldone = readl(>emmcphy_status); > + caldone = (caldone >> PHYCTRL_CALDONE_SHIFT) & PHYCTRL_CALDONE_MASK; > + if (caldone != PHYCTRL_CALDONE_DONE) { > + printf("%s: caldone timeout.\n", __func__); > + return; > + } > + > + /* Set the frequency of the DLL operation */ > + if (clock < 75 * MHz) > + freqsel = PHYCTRL_FREQSEL_50M; > + else if (clock < 125 * MHz) > + freqsel = PHYCTRL_FREQSEL_100M; > + else if (clock < 175 * MHz) > + freqsel = PHYCTRL_FREQSEL_150M; > + else > + freqsel = PHYCTRL_FREQSEL_200M; > + > + /* Set the frequency of the DLL operation */ > + writel(RK_CLRSETBITS(3 << 12, freqsel << 12), >emmcphy_con[0]); > + writel(RK_CLRSETBITS(1 << 1, 1 << 1), >emmcphy_con[6]); > + > + read_poll_timeout(readl, >emmcphy_status, dllrdy, > + PHYCTRL_DLL_LOCK_WO_TMOUT(dllrdy), 1, 5000); > +} > + > +static
Re: [PATCH v3 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399
On 6/29/21 5:24 PM, Yifeng Zhao wrote: > Add clock, phy and other configuration, it is convenient to support > new controller. Here a short summary of the changes: > - Add mmc_of_parse to parse dts config. > - Remove OF_PLATDATA related code. > - Reorder header inclusion. > - Add phy ops. > - add ops set_ios_post to modify the parameters of phy when the > clock changes. > - Add execute tuning api for hs200 tuning. > > Signed-off-by: Yifeng Zhao Reviewed-by: Jaehoon Chung Best Regards, Jaehoon Chung > --- > > Changes in v3: > - Optimize hs200 tuning function. > - Add check for callback function. > - Add return value for tuning function. > - Fixed source clock rate with host->max_clk, the interface clock is divided > from the source clock. > > Changes in v2: > - Add mmc_of_parse to parse dts config. > - Used read_poll_timeout api to check dll lock status > - Add execute tuning api for hs200 tuning > > drivers/mmc/rockchip_sdhci.c | 313 +++ > 1 file changed, 277 insertions(+), 36 deletions(-) > > diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c > index d95f8b2a15..eff134c8f5 100644 > --- a/drivers/mmc/rockchip_sdhci.c > +++ b/drivers/mmc/rockchip_sdhci.c > @@ -6,90 +6,322 @@ > */ > > #include > +#include > #include > +#include > #include > +#include > #include > #include > +#include > #include > #include > +#include "mmc_private.h" > #include > -#include > +#include > +#include > +#include > > /* 400KHz is max freq for card ID etc. Use that as min */ > #define EMMC_MIN_FREQ40 > +#define KHz (1000) > +#define MHz (1000 * KHz) > +#define SDHCI_TUNING_LOOP_COUNT 40 > + > +#define PHYCTRL_CALDONE_MASK 0x1 > +#define PHYCTRL_CALDONE_SHIFT0x6 > +#define PHYCTRL_CALDONE_DONE 0x1 > +#define PHYCTRL_DLLRDY_MASK 0x1 > +#define PHYCTRL_DLLRDY_SHIFT 0x5 > +#define PHYCTRL_DLLRDY_DONE 0x1 > +#define PHYCTRL_FREQSEL_200M 0x0 > +#define PHYCTRL_FREQSEL_50M 0x1 > +#define PHYCTRL_FREQSEL_100M 0x2 > +#define PHYCTRL_FREQSEL_150M 0x3 > +#define PHYCTRL_DLL_LOCK_WO_TMOUT(x) \ > + x) >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK) ==\ > + PHYCTRL_DLLRDY_DONE) > > struct rockchip_sdhc_plat { > -#if CONFIG_IS_ENABLED(OF_PLATDATA) > - struct dtd_rockchip_rk3399_sdhci_5_1 dtplat; > -#endif > struct mmc_config cfg; > struct mmc mmc; > }; > > +struct rockchip_emmc_phy { > + u32 emmcphy_con[7]; > + u32 reserved; > + u32 emmcphy_status; > +}; > + > struct rockchip_sdhc { > struct sdhci_host host; > + struct udevice *dev; > void *base; > + struct rockchip_emmc_phy *phy; > + struct clk emmc_clk; > +}; > + > +struct sdhci_data { > + int (*emmc_set_clock)(struct sdhci_host *host, unsigned int clock); > + int (*emmc_phy_init)(struct udevice *dev); > + int (*get_phy)(struct udevice *dev); > +}; > + > +static int rk3399_emmc_phy_init(struct udevice *dev) > +{ > + return 0; > +} > + > +static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 > clock) > +{ > + u32 caldone, dllrdy, freqsel; > + > + writel(RK_CLRSETBITS(7 << 4, 0), >emmcphy_con[6]); > + writel(RK_CLRSETBITS(1 << 11, 1 << 11), >emmcphy_con[0]); > + writel(RK_CLRSETBITS(0xf << 7, 6 << 7), >emmcphy_con[0]); > + > + /* > + * According to the user manual, calpad calibration > + * cycle takes more than 2us without the minimal recommended > + * value, so we may need a little margin here > + */ > + udelay(3); > + writel(RK_CLRSETBITS(1, 1), >emmcphy_con[6]); > + > + /* > + * According to the user manual, it asks driver to > + * wait 5us for calpad busy trimming. But it seems that > + * 5us of caldone isn't enough for all cases. > + */ > + udelay(500); > + caldone = readl(>emmcphy_status); > + caldone = (caldone >> PHYCTRL_CALDONE_SHIFT) & PHYCTRL_CALDONE_MASK; > + if (caldone != PHYCTRL_CALDONE_DONE) { > + printf("%s: caldone timeout.\n", __func__); > + return; > + } > + > + /* Set the frequency of the DLL operation */ > + if (clock < 75 * MHz) > + freqsel = PHYCTRL_FREQSEL_50M; > + else if (clock < 125 * MHz) > + freqsel = PHYCTRL_FREQSEL_100M; > + else if (clock < 175 * MHz) > + freqsel = PHYCTRL_FREQSEL_150M; > + else > + freqsel = PHYCTRL_FREQSEL_200M; > + > + /* Set the frequency of the DLL operation */ > + writel(RK_CLRSETBITS(3 << 12, freqsel << 12), >emmcphy_con[0]); > + writel(RK_CLRSETBITS(1 << 1, 1 << 1), >emmcphy_con[6]); > + > + read_poll_timeout(readl, >emmcphy_status, dllrdy, > + PHYCTRL_DLL_LOCK_WO_TMOUT(dllrdy), 1, 5000); > +} > + > +static void rk3399_emmc_phy_power_off(struct rockchip_emmc_phy *phy) > +{ > +
[PATCH v3 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399
Add clock, phy and other configuration, it is convenient to support new controller. Here a short summary of the changes: - Add mmc_of_parse to parse dts config. - Remove OF_PLATDATA related code. - Reorder header inclusion. - Add phy ops. - add ops set_ios_post to modify the parameters of phy when the clock changes. - Add execute tuning api for hs200 tuning. Signed-off-by: Yifeng Zhao --- Changes in v3: - Optimize hs200 tuning function. - Add check for callback function. - Add return value for tuning function. - Fixed source clock rate with host->max_clk, the interface clock is divided from the source clock. Changes in v2: - Add mmc_of_parse to parse dts config. - Used read_poll_timeout api to check dll lock status - Add execute tuning api for hs200 tuning drivers/mmc/rockchip_sdhci.c | 313 +++ 1 file changed, 277 insertions(+), 36 deletions(-) diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c index d95f8b2a15..eff134c8f5 100644 --- a/drivers/mmc/rockchip_sdhci.c +++ b/drivers/mmc/rockchip_sdhci.c @@ -6,90 +6,322 @@ */ #include +#include #include +#include #include +#include #include #include +#include #include #include +#include "mmc_private.h" #include -#include +#include +#include +#include /* 400KHz is max freq for card ID etc. Use that as min */ #define EMMC_MIN_FREQ 40 +#define KHz(1000) +#define MHz(1000 * KHz) +#define SDHCI_TUNING_LOOP_COUNT40 + +#define PHYCTRL_CALDONE_MASK 0x1 +#define PHYCTRL_CALDONE_SHIFT 0x6 +#define PHYCTRL_CALDONE_DONE 0x1 +#define PHYCTRL_DLLRDY_MASK0x1 +#define PHYCTRL_DLLRDY_SHIFT 0x5 +#define PHYCTRL_DLLRDY_DONE0x1 +#define PHYCTRL_FREQSEL_200M 0x0 +#define PHYCTRL_FREQSEL_50M0x1 +#define PHYCTRL_FREQSEL_100M 0x2 +#define PHYCTRL_FREQSEL_150M 0x3 +#define PHYCTRL_DLL_LOCK_WO_TMOUT(x) \ + x) >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK) ==\ + PHYCTRL_DLLRDY_DONE) struct rockchip_sdhc_plat { -#if CONFIG_IS_ENABLED(OF_PLATDATA) - struct dtd_rockchip_rk3399_sdhci_5_1 dtplat; -#endif struct mmc_config cfg; struct mmc mmc; }; +struct rockchip_emmc_phy { + u32 emmcphy_con[7]; + u32 reserved; + u32 emmcphy_status; +}; + struct rockchip_sdhc { struct sdhci_host host; + struct udevice *dev; void *base; + struct rockchip_emmc_phy *phy; + struct clk emmc_clk; +}; + +struct sdhci_data { + int (*emmc_set_clock)(struct sdhci_host *host, unsigned int clock); + int (*emmc_phy_init)(struct udevice *dev); + int (*get_phy)(struct udevice *dev); +}; + +static int rk3399_emmc_phy_init(struct udevice *dev) +{ + return 0; +} + +static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 clock) +{ + u32 caldone, dllrdy, freqsel; + + writel(RK_CLRSETBITS(7 << 4, 0), >emmcphy_con[6]); + writel(RK_CLRSETBITS(1 << 11, 1 << 11), >emmcphy_con[0]); + writel(RK_CLRSETBITS(0xf << 7, 6 << 7), >emmcphy_con[0]); + + /* +* According to the user manual, calpad calibration +* cycle takes more than 2us without the minimal recommended +* value, so we may need a little margin here +*/ + udelay(3); + writel(RK_CLRSETBITS(1, 1), >emmcphy_con[6]); + + /* +* According to the user manual, it asks driver to +* wait 5us for calpad busy trimming. But it seems that +* 5us of caldone isn't enough for all cases. +*/ + udelay(500); + caldone = readl(>emmcphy_status); + caldone = (caldone >> PHYCTRL_CALDONE_SHIFT) & PHYCTRL_CALDONE_MASK; + if (caldone != PHYCTRL_CALDONE_DONE) { + printf("%s: caldone timeout.\n", __func__); + return; + } + + /* Set the frequency of the DLL operation */ + if (clock < 75 * MHz) + freqsel = PHYCTRL_FREQSEL_50M; + else if (clock < 125 * MHz) + freqsel = PHYCTRL_FREQSEL_100M; + else if (clock < 175 * MHz) + freqsel = PHYCTRL_FREQSEL_150M; + else + freqsel = PHYCTRL_FREQSEL_200M; + + /* Set the frequency of the DLL operation */ + writel(RK_CLRSETBITS(3 << 12, freqsel << 12), >emmcphy_con[0]); + writel(RK_CLRSETBITS(1 << 1, 1 << 1), >emmcphy_con[6]); + + read_poll_timeout(readl, >emmcphy_status, dllrdy, + PHYCTRL_DLL_LOCK_WO_TMOUT(dllrdy), 1, 5000); +} + +static void rk3399_emmc_phy_power_off(struct rockchip_emmc_phy *phy) +{ + writel(RK_CLRSETBITS(1, 0), >emmcphy_con[6]); + writel(RK_CLRSETBITS(1 << 1, 0), >emmcphy_con[6]); +} + +static int rk3399_emmc_get_phy(struct udevice *dev) +{ + struct rockchip_sdhc *priv = dev_get_priv(dev); + ofnode phy_node; + void *grf_base; + u32 grf_phy_offset, phandle; +