All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/3]
@ 2021-06-28  9:19 Yifeng Zhao
  2021-06-28  9:19 ` [PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399 Yifeng Zhao
                   ` (3 more replies)
  0 siblings, 4 replies; 14+ messages in thread
From: Yifeng Zhao @ 2021-06-28  9:19 UTC (permalink / raw)
  To: Jaehoon Chung, sjg, Kever Yang
  Cc: Peng Fan, Philipp Tomsich, u-boot, Yifeng Zhao

RK3399 and RK3568 are use different sdhci controllers.
The drivers need to be updated to support these two platforms
and it's easy to support new platforms.


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
- Used sdhci_set_clock api to set clock.
- Used read_poll_timeout api to check dll status.

Yifeng Zhao (3):
  mmc: rockchip_sdhci: add phy and clock config for rk3399
  mmc: rockchip_sdhci: Add support for RK3568
  rockchip: config: evb-rk3399: add hs200 and hs400 support

 configs/evb-rk3399_defconfig |   1 +
 drivers/mmc/rockchip_sdhci.c | 427 ++++++++++++++++++++++++++++++++---
 2 files changed, 392 insertions(+), 36 deletions(-)

-- 
2.17.1




^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399
  2021-06-28  9:19 [PATCH v2 0/3] Yifeng Zhao
@ 2021-06-28  9:19 ` Yifeng Zhao
  2021-06-29  0:40   ` Jaehoon Chung
                     ` (2 more replies)
  2021-06-28  9:19 ` [PATCH v2 2/3] mmc: rockchip_sdhci: Add support for RK3568 Yifeng Zhao
                   ` (2 subsequent siblings)
  3 siblings, 3 replies; 14+ messages in thread
From: Yifeng Zhao @ 2021-06-28  9:19 UTC (permalink / raw)
  To: Jaehoon Chung, sjg, Kever Yang
  Cc: Peng Fan, Philipp Tomsich, u-boot, Yifeng Zhao

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 <yifeng.zhao@rock-chips.com>
---

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 | 310 +++++++++++++++++++++++++++++++----
 1 file changed, 274 insertions(+), 36 deletions(-)

diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
index d95f8b2a15..2973911446 100644
--- a/drivers/mmc/rockchip_sdhci.c
+++ b/drivers/mmc/rockchip_sdhci.c
@@ -6,90 +6,319 @@
  */
 
 #include <common.h>
+#include <clk.h>
 #include <dm.h>
+#include <dm/ofnode.h>
 #include <dt-structs.h>
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/libfdt.h>
+#include <linux/iopoll.h>
 #include <malloc.h>
 #include <mapmem.h>
+#include "mmc_private.h"
 #include <sdhci.h>
-#include <clk.h>
+#include <syscon.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/hardware.h>
 
 /* 400KHz is max freq for card ID etc. Use that as min */
 #define EMMC_MIN_FREQ	400000
+#define KHz	(1000)
+#define MHz	(1000 * KHz)
+#define SDHCI_TUNING_LOOP_COUNT		40
+
+#define PHYCTRL_CALDONE_MASK		0x1
+#define PHYCTRL_CALDONE_SHIFT		0x6
+#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), &phy->emmcphy_con[6]);
+	writel(RK_CLRSETBITS(1 << 11, 1 << 11), &phy->emmcphy_con[0]);
+	writel(RK_CLRSETBITS(0xf << 7, 6 << 7), &phy->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), &phy->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(&phy->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), &phy->emmcphy_con[0]);
+	writel(RK_CLRSETBITS(1 << 1, 1 << 1), &phy->emmcphy_con[6]);
+
+	read_poll_timeout(readl, &phy->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), &phy->emmcphy_con[6]);
+	writel(RK_CLRSETBITS(1 << 1, 0), &phy->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;
+
+	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;
+	}
+
+	grf_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+	if (grf_base < 0)
+		printf("%s Get syscon grf failed", __func__);
+	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;
+	int max_clk = host->max_clk;
+	unsigned long mmc_clock;
+
+	if (cycle_phy)
+		rk3399_emmc_phy_power_off(priv->phy);
+
+	if (clock) {
+		mmc_clock = clk_set_rate(&priv->emmc_clk, clock);
+		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;
+
+	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;
+	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;
+	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);
+
+	do {
+		cmd.cmdidx = opcode;
+		cmd.resp_type = MMC_RSP_R1;
+		cmd.cmdarg = 0;
+
+		if (tuning_loop_counter-- == 0)
+			break;
+
+		if (opcode == MMC_CMD_SEND_TUNING_BLOCK_HS200 && host->mmc->bus_width == 8)
+			sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128), SDHCI_BLOCK_SIZE);
+		else
+			sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE);
+
+		sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
+
+		mmc_send_cmd(mmc, &cmd, NULL);
+
+		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 = -1;
+	}
+
+	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, SDHCI_INT_ENABLE);
+	/* Mask all sdhci interrupt sources */
+	sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);
+
+	return 0;
+}
+
+static struct sdhci_ops rockchip_sdhci_ops = {
+	.set_ios_post	= rockchip_sdhci_set_ios_post,
+	.platform_execute_tuning = &rockchip_sdhci_execute_tuning,
 };
 
-static int arasan_sdhci_probe(struct udevice *dev)
+static int rockchip_sdhci_probe(struct udevice *dev)
 {
+	struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(dev);
 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
 	struct rockchip_sdhc_plat *plat = dev_get_plat(dev);
 	struct rockchip_sdhc *prv = dev_get_priv(dev);
+	struct mmc_config *cfg = &plat->cfg;
 	struct sdhci_host *host = &prv->host;
-	int max_frequency, ret;
 	struct clk clk;
+	int ret;
 
-#if CONFIG_IS_ENABLED(OF_PLATDATA)
-	struct dtd_rockchip_rk3399_sdhci_5_1 *dtplat = &plat->dtplat;
-
-	host->name = dev->name;
-	host->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
-	max_frequency = dtplat->max_frequency;
-	ret = clk_get_by_driver_info(dev, dtplat->clocks, &clk);
-#else
-	max_frequency = dev_read_u32_default(dev, "max-frequency", 0);
+	host->max_clk = cfg->f_max;
 	ret = clk_get_by_index(dev, 0, &clk);
-#endif
 	if (!ret) {
-		ret = clk_set_rate(&clk, max_frequency);
+		ret = clk_set_rate(&clk, host->max_clk);
 		if (IS_ERR_VALUE(ret))
 			printf("%s clk set rate fail!\n", __func__);
 	} else {
 		printf("%s fail to get clk\n", __func__);
 	}
 
+	prv->emmc_clk = clk;
+	prv->dev = dev;
+	ret = data->get_phy(dev);
+	if (ret)
+		return ret;
+
+	ret = data->emmc_phy_init(dev);
+	if (ret)
+		return ret;
+
+	host->ops = &rockchip_sdhci_ops;
+
 	host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
-	host->max_clk = max_frequency;
-	/*
-	 * The sdhci-driver only supports 4bit and 8bit, as sdhci_setup_cfg
-	 * doesn't allow us to clear MMC_MODE_4BIT.  Consequently, we don't
-	 * check for other bus-width values.
-	 */
-	if (host->bus_width == 8)
-		host->host_caps |= MMC_MODE_8BIT;
 
 	host->mmc = &plat->mmc;
 	host->mmc->priv = &prv->host;
 	host->mmc->dev = dev;
 	upriv->mmc = host->mmc;
 
-	ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ);
+	ret = sdhci_setup_cfg(cfg, host, cfg->f_max, EMMC_MIN_FREQ);
 	if (ret)
 		return ret;
 
 	return sdhci_probe(dev);
 }
 
-static int arasan_sdhci_of_to_plat(struct udevice *dev)
+static int rockchip_sdhci_of_to_plat(struct udevice *dev)
 {
-#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct rockchip_sdhc_plat *plat = dev_get_plat(dev);
 	struct sdhci_host *host = dev_get_priv(dev);
+	struct mmc_config *cfg = &plat->cfg;
+	int ret;
 
 	host->name = dev->name;
 	host->ioaddr = dev_read_addr_ptr(dev);
-	host->bus_width = dev_read_u32_default(dev, "bus-width", 4);
-#endif
+
+	ret = mmc_of_parse(dev, cfg);
+	if (ret)
+		return ret;
 
 	return 0;
 }
@@ -101,19 +330,28 @@ static int rockchip_sdhci_bind(struct udevice *dev)
 	return sdhci_bind(dev, &plat->mmc, &plat->cfg);
 }
 
-static const struct udevice_id arasan_sdhci_ids[] = {
-	{ .compatible = "arasan,sdhci-5.1" },
+static const struct sdhci_data rk3399_data = {
+	.emmc_set_clock = rk3399_sdhci_emmc_set_clock,
+	.get_phy = rk3399_emmc_get_phy,
+	.emmc_phy_init = rk3399_emmc_phy_init,
+};
+
+static const struct udevice_id sdhci_ids[] = {
+	{
+		.compatible = "arasan,sdhci-5.1",
+		.data = (ulong)&rk3399_data,
+	},
 	{ }
 };
 
 U_BOOT_DRIVER(arasan_sdhci_drv) = {
-	.name		= "rockchip_rk3399_sdhci_5_1",
+	.name		= "rockchip_sdhci_5_1",
 	.id		= UCLASS_MMC,
-	.of_match	= arasan_sdhci_ids,
-	.of_to_plat = arasan_sdhci_of_to_plat,
+	.of_match	= sdhci_ids,
+	.of_to_plat	= rockchip_sdhci_of_to_plat,
 	.ops		= &sdhci_ops,
 	.bind		= rockchip_sdhci_bind,
-	.probe		= arasan_sdhci_probe,
+	.probe		= rockchip_sdhci_probe,
 	.priv_auto	= sizeof(struct rockchip_sdhc),
 	.plat_auto	= sizeof(struct rockchip_sdhc_plat),
 };
-- 
2.17.1




^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 2/3] mmc: rockchip_sdhci: Add support for RK3568
  2021-06-28  9:19 [PATCH v2 0/3] Yifeng Zhao
  2021-06-28  9:19 ` [PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399 Yifeng Zhao
@ 2021-06-28  9:19 ` Yifeng Zhao
  2021-06-29  0:45   ` Jaehoon Chung
  2021-06-28  9:19 ` [PATCH v2 3/3] rockchip: config: evb-rk3399: add hs200 and hs400 support Yifeng Zhao
  2021-06-28  9:25 ` [PATCH v2 0/3] Philipp Tomsich
  3 siblings, 1 reply; 14+ messages in thread
From: Yifeng Zhao @ 2021-06-28  9:19 UTC (permalink / raw)
  To: Jaehoon Chung, sjg, Kever Yang
  Cc: Peng Fan, Philipp Tomsich, u-boot, Yifeng Zhao

This patch adds support for the RK3568 platform to this driver.

Signed-off-by: Yifeng Zhao <yifeng.zhao@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);
+		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;
+
+	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,
+	},
 	{ }
 };
 
-- 
2.17.1




^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 3/3] rockchip: config: evb-rk3399: add hs200 and hs400 support
  2021-06-28  9:19 [PATCH v2 0/3] Yifeng Zhao
  2021-06-28  9:19 ` [PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399 Yifeng Zhao
  2021-06-28  9:19 ` [PATCH v2 2/3] mmc: rockchip_sdhci: Add support for RK3568 Yifeng Zhao
@ 2021-06-28  9:19 ` Yifeng Zhao
  2021-06-28  9:21   ` Philipp Tomsich
  2021-06-28  9:25 ` [PATCH v2 0/3] Philipp Tomsich
  3 siblings, 1 reply; 14+ messages in thread
From: Yifeng Zhao @ 2021-06-28  9:19 UTC (permalink / raw)
  To: Jaehoon Chung, sjg, Kever Yang
  Cc: Peng Fan, Philipp Tomsich, u-boot, Yifeng Zhao

This enable hs200 and hs400 support for emmc on evb-rk3399.

Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
---

(no changes since v1)

 configs/evb-rk3399_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/configs/evb-rk3399_defconfig b/configs/evb-rk3399_defconfig
index 909c68822c..687aeec26c 100644
--- a/configs/evb-rk3399_defconfig
+++ b/configs/evb-rk3399_defconfig
@@ -29,6 +29,7 @@ CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_ROCKCHIP_GPIO=y
 CONFIG_SYS_I2C_ROCKCHIP=y
 CONFIG_MISC=y
+CONFIG_MMC_HS400_SUPPORT=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_DW_ROCKCHIP=y
 CONFIG_MMC_SDHCI=y
-- 
2.17.1




^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 3/3] rockchip: config: evb-rk3399: add hs200 and hs400 support
  2021-06-28  9:19 ` [PATCH v2 3/3] rockchip: config: evb-rk3399: add hs200 and hs400 support Yifeng Zhao
@ 2021-06-28  9:21   ` Philipp Tomsich
  0 siblings, 0 replies; 14+ messages in thread
From: Philipp Tomsich @ 2021-06-28  9:21 UTC (permalink / raw)
  To: Yifeng Zhao; +Cc: Jaehoon Chung, sjg, Kever Yang, Peng Fan, U-Boot Mailing List

On Mon, 28 Jun 2021 at 11:20, Yifeng Zhao <yifeng.zhao@rock-chips.com> wrote:
>
> This enable hs200 and hs400 support for emmc on evb-rk3399.
>
> Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>

Reviewed-by: Philipp Tomsich <philipp.tomsich@vrull.eu>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 0/3]
  2021-06-28  9:19 [PATCH v2 0/3] Yifeng Zhao
                   ` (2 preceding siblings ...)
  2021-06-28  9:19 ` [PATCH v2 3/3] rockchip: config: evb-rk3399: add hs200 and hs400 support Yifeng Zhao
@ 2021-06-28  9:25 ` Philipp Tomsich
  2021-06-28  9:32   ` Peter Robinson
  3 siblings, 1 reply; 14+ messages in thread
From: Philipp Tomsich @ 2021-06-28  9:25 UTC (permalink / raw)
  To: Yifeng Zhao; +Cc: Jaehoon Chung, sjg, Kever Yang, Peng Fan, U-Boot Mailing List

I had attempted to merge HDMI using this approach in 2017, but after
some discussions with Simon, we used a 'mini-drivers' approach.
I would like to see a similar approach taken here.

See
https://patchwork.ozlabs.org/project/uboot/patch/1493394792-20743-4-git-send-email-philipp.tomsich@theobroma-systems.com/#1650260
for the original discussion between Simon and me.

Thanks,
Philipp.


On Mon, 28 Jun 2021 at 11:20, Yifeng Zhao <yifeng.zhao@rock-chips.com>
wrote:

> RK3399 and RK3568 are use different sdhci controllers.
> The drivers need to be updated to support these two platforms
> and it's easy to support new platforms.
>
>
> 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
> - Used sdhci_set_clock api to set clock.
> - Used read_poll_timeout api to check dll status.
>
> Yifeng Zhao (3):
>   mmc: rockchip_sdhci: add phy and clock config for rk3399
>   mmc: rockchip_sdhci: Add support for RK3568
>   rockchip: config: evb-rk3399: add hs200 and hs400 support
>
>  configs/evb-rk3399_defconfig |   1 +
>  drivers/mmc/rockchip_sdhci.c | 427 ++++++++++++++++++++++++++++++++---
>  2 files changed, 392 insertions(+), 36 deletions(-)
>
> --
> 2.17.1
>
>
>
>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 0/3]
  2021-06-28  9:25 ` [PATCH v2 0/3] Philipp Tomsich
@ 2021-06-28  9:32   ` Peter Robinson
  0 siblings, 0 replies; 14+ messages in thread
From: Peter Robinson @ 2021-06-28  9:32 UTC (permalink / raw)
  To: Philipp Tomsich
  Cc: Yifeng Zhao, Jaehoon Chung, sjg, Kever Yang, Peng Fan,
	U-Boot Mailing List

Was the original mails of this series sent to the list? I don't see
them in the archives or patchwork.

On Mon, Jun 28, 2021 at 10:26 AM Philipp Tomsich
<philipp.tomsich@vrull.eu> wrote:
>
> I had attempted to merge HDMI using this approach in 2017, but after
> some discussions with Simon, we used a 'mini-drivers' approach.
> I would like to see a similar approach taken here.
>
> See
> https://patchwork.ozlabs.org/project/uboot/patch/1493394792-20743-4-git-send-email-philipp.tomsich@theobroma-systems.com/#1650260
> for the original discussion between Simon and me.
>
> Thanks,
> Philipp.
>
>
> On Mon, 28 Jun 2021 at 11:20, Yifeng Zhao <yifeng.zhao@rock-chips.com>
> wrote:
>
> > RK3399 and RK3568 are use different sdhci controllers.
> > The drivers need to be updated to support these two platforms
> > and it's easy to support new platforms.
> >
> >
> > 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
> > - Used sdhci_set_clock api to set clock.
> > - Used read_poll_timeout api to check dll status.
> >
> > Yifeng Zhao (3):
> >   mmc: rockchip_sdhci: add phy and clock config for rk3399
> >   mmc: rockchip_sdhci: Add support for RK3568
> >   rockchip: config: evb-rk3399: add hs200 and hs400 support
> >
> >  configs/evb-rk3399_defconfig |   1 +
> >  drivers/mmc/rockchip_sdhci.c | 427 ++++++++++++++++++++++++++++++++---
> >  2 files changed, 392 insertions(+), 36 deletions(-)
> >
> > --
> > 2.17.1
> >
> >
> >
> >

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399
  2021-06-28  9:19 ` [PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399 Yifeng Zhao
@ 2021-06-29  0:40   ` Jaehoon Chung
  2021-06-29  7:15     ` 赵仪峰
  2021-06-30  1:08   ` Peng Fan (OSS)
  2021-06-30  1:11   ` Peng Fan (OSS)
  2 siblings, 1 reply; 14+ messages in thread
From: Jaehoon Chung @ 2021-06-29  0:40 UTC (permalink / raw)
  To: Yifeng Zhao, sjg, Kever Yang; +Cc: Peng Fan, Philipp Tomsich, u-boot

Hi Yifeng,

On 6/28/21 6:19 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 <yifeng.zhao@rock-chips.com>
> ---
> 
> 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 | 310 +++++++++++++++++++++++++++++++----
>  1 file changed, 274 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
> index d95f8b2a15..2973911446 100644
> --- a/drivers/mmc/rockchip_sdhci.c
> +++ b/drivers/mmc/rockchip_sdhci.c
> @@ -6,90 +6,319 @@
>   */
>  
>  #include <common.h>
> +#include <clk.h>
>  #include <dm.h>
> +#include <dm/ofnode.h>
>  #include <dt-structs.h>
> +#include <linux/delay.h>
>  #include <linux/err.h>
>  #include <linux/libfdt.h>
> +#include <linux/iopoll.h>
>  #include <malloc.h>
>  #include <mapmem.h>
> +#include "mmc_private.h"
>  #include <sdhci.h>
> -#include <clk.h>
> +#include <syscon.h>
> +#include <asm/arch-rockchip/clock.h>
> +#include <asm/arch-rockchip/hardware.h>
>  
>  /* 400KHz is max freq for card ID etc. Use that as min */
>  #define EMMC_MIN_FREQ	400000
> +#define KHz	(1000)
> +#define MHz	(1000 * KHz)
> +#define SDHCI_TUNING_LOOP_COUNT		40
> +
> +#define PHYCTRL_CALDONE_MASK		0x1
> +#define PHYCTRL_CALDONE_SHIFT		0x6
> +#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), &phy->emmcphy_con[6]);

RK_CLRSETBITS macro is (((clr) | (set))) << 16) | (set).
Which bit is cleared? When (7 << 4) is set, it means that cleared?


> +	writel(RK_CLRSETBITS(1 << 11, 1 << 11), &phy->emmcphy_con[0]);
> +	writel(RK_CLRSETBITS(0xf << 7, 6 << 7), &phy->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), &phy->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(&phy->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), &phy->emmcphy_con[0]);
> +	writel(RK_CLRSETBITS(1 << 1, 1 << 1), &phy->emmcphy_con[6]);
> +
> +	read_poll_timeout(readl, &phy->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), &phy->emmcphy_con[6]);
> +	writel(RK_CLRSETBITS(1 << 1, 0), &phy->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;
> +
> +	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;
> +	}
> +
> +	grf_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
> +	if (grf_base < 0)
> +		printf("%s Get syscon grf failed", __func__);
> +	grf_phy_offset = ofnode_read_u32_default(phy_node, "reg", 0);
> +
> +	priv->phy = (struct rockchip_emmc_phy *)(grf_base + grf_phy_offset);

If grf_base is failed to get, is (grf_base + grp_phy_offset) correct?

> +
> +	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;
> +	int max_clk = host->max_clk;
> +	unsigned long mmc_clock;
> +
> +	if (cycle_phy)
> +		rk3399_emmc_phy_power_off(priv->phy);
> +
> +	if (clock) {
> +		mmc_clock = clk_set_rate(&priv->emmc_clk, clock);
> +		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;
> +
> +	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;
> +	data->emmc_set_clock(host, clock);

I think that it needs to check whether callback function is null or not.
It's possible to exist the case that not to assign to callback function in future.

> +
> +	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;
> +	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);
> +
> +	do {
> +		cmd.cmdidx = opcode;
> +		cmd.resp_type = MMC_RSP_R1;
> +		cmd.cmdarg = 0;
> +
> +		if (tuning_loop_counter-- == 0)
> +			break;
> +
> +		if (opcode == MMC_CMD_SEND_TUNING_BLOCK_HS200 && host->mmc->bus_width == 8)
> +			sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128), SDHCI_BLOCK_SIZE);
> +		else
> +			sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE);

Why it needs to pass to 7? It seems that always (dma & 0x7) in SDHCI_MAKE_BLKSZ.
#define SDHCI_MAKE_BLKSZ(blksz) (1 << 12) | (blksz & 0xFFF)?


> +
> +		sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
> +
> +		mmc_send_cmd(mmc, &cmd, NULL);
> +
> +		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 = -1;
> +	}
> +
> +	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, SDHCI_INT_ENABLE);
> +	/* Mask all sdhci interrupt sources */
> +	sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);
> +
> +	return 0;

Doesn't need to return "ret" when it's failed?

> +}
> +
> +static struct sdhci_ops rockchip_sdhci_ops = {
> +	.set_ios_post	= rockchip_sdhci_set_ios_post,
> +	.platform_execute_tuning = &rockchip_sdhci_execute_tuning,
>  };
>  
> -static int arasan_sdhci_probe(struct udevice *dev)
> +static int rockchip_sdhci_probe(struct udevice *dev)
>  {
> +	struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(dev);
>  	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
>  	struct rockchip_sdhc_plat *plat = dev_get_plat(dev);
>  	struct rockchip_sdhc *prv = dev_get_priv(dev);
> +	struct mmc_config *cfg = &plat->cfg;
>  	struct sdhci_host *host = &prv->host;
> -	int max_frequency, ret;
>  	struct clk clk;
> +	int ret;
>  
> -#if CONFIG_IS_ENABLED(OF_PLATDATA)
> -	struct dtd_rockchip_rk3399_sdhci_5_1 *dtplat = &plat->dtplat;
> -
> -	host->name = dev->name;
> -	host->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
> -	max_frequency = dtplat->max_frequency;
> -	ret = clk_get_by_driver_info(dev, dtplat->clocks, &clk);
> -#else
> -	max_frequency = dev_read_u32_default(dev, "max-frequency", 0);
> +	host->max_clk = cfg->f_max;
>  	ret = clk_get_by_index(dev, 0, &clk);
> -#endif
>  	if (!ret) {
> -		ret = clk_set_rate(&clk, max_frequency);
> +		ret = clk_set_rate(&clk, host->max_clk);
>  		if (IS_ERR_VALUE(ret))
>  			printf("%s clk set rate fail!\n", __func__);
>  	} else {
>  		printf("%s fail to get clk\n", __func__);
>  	}
>  
> +	prv->emmc_clk = clk;
> +	prv->dev = dev;
> +	ret = data->get_phy(dev);

Ditto. Check data->get_phy.

> +	if (ret)
> +		return ret;
> +
> +	ret = data->emmc_phy_init(dev);

Ditto.

Best Regards,
Jaehoon Chung

> +	if (ret)
> +		return ret;
> +
> +	host->ops = &rockchip_sdhci_ops;
> +
>  	host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
> -	host->max_clk = max_frequency;
> -	/*
> -	 * The sdhci-driver only supports 4bit and 8bit, as sdhci_setup_cfg
> -	 * doesn't allow us to clear MMC_MODE_4BIT.  Consequently, we don't
> -	 * check for other bus-width values.
> -	 */
> -	if (host->bus_width == 8)
> -		host->host_caps |= MMC_MODE_8BIT;
>  
>  	host->mmc = &plat->mmc;
>  	host->mmc->priv = &prv->host;
>  	host->mmc->dev = dev;
>  	upriv->mmc = host->mmc;
>  
> -	ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ);
> +	ret = sdhci_setup_cfg(cfg, host, cfg->f_max, EMMC_MIN_FREQ);
>  	if (ret)
>  		return ret;
>  
>  	return sdhci_probe(dev);
>  }
>  
> -static int arasan_sdhci_of_to_plat(struct udevice *dev)
> +static int rockchip_sdhci_of_to_plat(struct udevice *dev)
>  {
> -#if !CONFIG_IS_ENABLED(OF_PLATDATA)
> +	struct rockchip_sdhc_plat *plat = dev_get_plat(dev);
>  	struct sdhci_host *host = dev_get_priv(dev);
> +	struct mmc_config *cfg = &plat->cfg;
> +	int ret;
>  
>  	host->name = dev->name;
>  	host->ioaddr = dev_read_addr_ptr(dev);
> -	host->bus_width = dev_read_u32_default(dev, "bus-width", 4);
> -#endif
> +
> +	ret = mmc_of_parse(dev, cfg);
> +	if (ret)
> +		return ret;
>  
>  	return 0;
>  }
> @@ -101,19 +330,28 @@ static int rockchip_sdhci_bind(struct udevice *dev)
>  	return sdhci_bind(dev, &plat->mmc, &plat->cfg);
>  }
>  
> -static const struct udevice_id arasan_sdhci_ids[] = {
> -	{ .compatible = "arasan,sdhci-5.1" },
> +static const struct sdhci_data rk3399_data = {
> +	.emmc_set_clock = rk3399_sdhci_emmc_set_clock,
> +	.get_phy = rk3399_emmc_get_phy,
> +	.emmc_phy_init = rk3399_emmc_phy_init,
> +};
> +
> +static const struct udevice_id sdhci_ids[] = {
> +	{
> +		.compatible = "arasan,sdhci-5.1",
> +		.data = (ulong)&rk3399_data,
> +	},
>  	{ }
>  };
>  
>  U_BOOT_DRIVER(arasan_sdhci_drv) = {
> -	.name		= "rockchip_rk3399_sdhci_5_1",
> +	.name		= "rockchip_sdhci_5_1",
>  	.id		= UCLASS_MMC,
> -	.of_match	= arasan_sdhci_ids,
> -	.of_to_plat = arasan_sdhci_of_to_plat,
> +	.of_match	= sdhci_ids,
> +	.of_to_plat	= rockchip_sdhci_of_to_plat,
>  	.ops		= &sdhci_ops,
>  	.bind		= rockchip_sdhci_bind,
> -	.probe		= arasan_sdhci_probe,
> +	.probe		= rockchip_sdhci_probe,
>  	.priv_auto	= sizeof(struct rockchip_sdhc),
>  	.plat_auto	= sizeof(struct rockchip_sdhc_plat),
>  };
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 2/3] mmc: rockchip_sdhci: Add support for RK3568
  2021-06-28  9:19 ` [PATCH v2 2/3] mmc: rockchip_sdhci: Add support for RK3568 Yifeng Zhao
@ 2021-06-29  0:45   ` Jaehoon Chung
  2021-06-29  2:07     ` 赵仪峰
  0 siblings, 1 reply; 14+ messages in thread
From: Jaehoon Chung @ 2021-06-29  0:45 UTC (permalink / raw)
  To: Yifeng Zhao, sjg, Kever Yang; +Cc: Peng Fan, Philipp Tomsich, u-boot

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.zhao@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;

> +		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?

> +
> +	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,
> +	},
>  	{ }
>  };
>  
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Re: [PATCH v2 2/3] mmc: rockchip_sdhci: Add support for RK3568
  2021-06-29  0:45   ` Jaehoon Chung
@ 2021-06-29  2:07     ` 赵仪峰
  2021-06-29  3:18       ` Jaehoon Chung
  0 siblings, 1 reply; 14+ messages in thread
From: 赵仪峰 @ 2021-06-29  2:07 UTC (permalink / raw)
  To: Jaehoon Chung, sjg, 杨凯; +Cc: Peng Fan, Philipp Tomsich, u-boot

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.zhao@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,



>> +	},



>>  	{ }



>>  };



>>  



>> 



>



>



>



>



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 2/3] mmc: rockchip_sdhci: Add support for RK3568
  2021-06-29  2:07     ` 赵仪峰
@ 2021-06-29  3:18       ` Jaehoon Chung
  0 siblings, 0 replies; 14+ messages in thread
From: Jaehoon Chung @ 2021-06-29  3:18 UTC (permalink / raw)
  To: 赵仪峰, sjg, 杨凯
  Cc: Peng Fan, Philipp Tomsich, u-boot

Hi,

On 6/29/21 11:07 AM, 赵仪峰 wrote:
> 
> 
> 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)

Thanks for kindly explanation. 
I didn't check its type. 

Best Regards,
Jaehoon Chung

> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Re: [PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399
  2021-06-29  0:40   ` Jaehoon Chung
@ 2021-06-29  7:15     ` 赵仪峰
  0 siblings, 0 replies; 14+ messages in thread
From: 赵仪峰 @ 2021-06-29  7:15 UTC (permalink / raw)
  To: Jaehoon Chung, sjg, 杨凯; +Cc: Peng Fan, Philipp Tomsich, u-boot

Hi Jaehoon,


>RK_CLRSETBITS macro is (((clr) | (set))) << 16) | (set).

>Which bit is cleared? When (7 << 4) is set, it means that cleared?

Yes, this ops clear the bit4-bit6.


>> +

>> +		if (opcode == MMC_CMD_SEND_TUNING_BLOCK_HS200 && host->mmc->bus_width == 8)

>> +			sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128), SDHCI_BLOCK_SIZE);

>> +		else

>> +			sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE);

>

>Why it needs to pass to 7? It seems that always (dma & 0x7) in SDHCI_MAKE_BLKSZ.

>#define SDHCI_MAKE_BLKSZ(blksz) (1 << 12) | (blksz & 0xFFF)?

In sdhci.h defined : 
#define  SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
....
#define SDHCI_DEFAULT_BOUNDARY_ARG	(7)

I will modify the code using SDHCI_DEFAULT_BOUNDARY_ARG, refer to iproc_sdhci.c

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);




>Hi Yifeng,



>



>On 6/28/21 6:19 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 <yifeng.zhao@rock-chips.com>



>> ---



>> 



>> 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 | 310 +++++++++++++++++++++++++++++++----



>>  1 file changed, 274 insertions(+), 36 deletions(-)



>> 



>> diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c



>> index d95f8b2a15..2973911446 100644



>> --- a/drivers/mmc/rockchip_sdhci.c



>> +++ b/drivers/mmc/rockchip_sdhci.c



>> @@ -6,90 +6,319 @@



>>   */



>>  



>>  #include <common.h>



>> +#include <clk.h>



>>  #include <dm.h>



>> +#include <dm/ofnode.h>



>>  #include <dt-structs.h>



>> +#include <linux/delay.h>



>>  #include <linux/err.h>



>>  #include <linux/libfdt.h>



>> +#include <linux/iopoll.h>



>>  #include <malloc.h>



>>  #include <mapmem.h>



>> +#include "mmc_private.h"



>>  #include <sdhci.h>



>> -#include <clk.h>



>> +#include <syscon.h>



>> +#include <asm/arch-rockchip/clock.h>



>> +#include <asm/arch-rockchip/hardware.h>



>>  



>>  /* 400KHz is max freq for card ID etc. Use that as min */



>>  #define EMMC_MIN_FREQ	400000



>> +#define KHz	(1000)



>> +#define MHz	(1000 * KHz)



>> +#define SDHCI_TUNING_LOOP_COUNT		40



>> +



>> +#define PHYCTRL_CALDONE_MASK		0x1



>> +#define PHYCTRL_CALDONE_SHIFT		0x6



>> +#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), &phy->emmcphy_con[6]);



>



>RK_CLRSETBITS macro is (((clr) | (set))) << 16) | (set).



>Which bit is cleared? When (7 << 4) is set, it means that cleared?



>



>



>> +	writel(RK_CLRSETBITS(1 << 11, 1 << 11), &phy->emmcphy_con[0]);



>> +	writel(RK_CLRSETBITS(0xf << 7, 6 << 7), &phy->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), &phy->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(&phy->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), &phy->emmcphy_con[0]);



>> +	writel(RK_CLRSETBITS(1 << 1, 1 << 1), &phy->emmcphy_con[6]);



>> +



>> +	read_poll_timeout(readl, &phy->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), &phy->emmcphy_con[6]);



>> +	writel(RK_CLRSETBITS(1 << 1, 0), &phy->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;



>> +



>> +	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;



>> +	}



>> +



>> +	grf_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);



>> +	if (grf_base < 0)



>> +		printf("%s Get syscon grf failed", __func__);



>> +	grf_phy_offset = ofnode_read_u32_default(phy_node, "reg", 0);



>> +



>> +	priv->phy = (struct rockchip_emmc_phy *)(grf_base + grf_phy_offset);



>



>If grf_base is failed to get, is (grf_base + grp_phy_offset) correct?



>



>> +



>> +	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;



>> +	int max_clk = host->max_clk;



>> +	unsigned long mmc_clock;



>> +



>> +	if (cycle_phy)



>> +		rk3399_emmc_phy_power_off(priv->phy);



>> +



>> +	if (clock) {



>> +		mmc_clock = clk_set_rate(&priv->emmc_clk, clock);



>> +		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;



>> +



>> +	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;



>> +	data->emmc_set_clock(host, clock);



>



>I think that it needs to check whether callback function is null or not.



>It's possible to exist the case that not to assign to callback function in future.



>



>> +



>> +	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;



>> +	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);



>> +



>> +	do {



>> +		cmd.cmdidx = opcode;



>> +		cmd.resp_type = MMC_RSP_R1;



>> +		cmd.cmdarg = 0;



>> +



>> +		if (tuning_loop_counter-- == 0)



>> +			break;



>> +



>> +		if (opcode == MMC_CMD_SEND_TUNING_BLOCK_HS200 && host->mmc->bus_width == 8)



>> +			sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128), SDHCI_BLOCK_SIZE);



>> +		else



>> +			sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE);



>



>Why it needs to pass to 7? It seems that always (dma & 0x7) in SDHCI_MAKE_BLKSZ.



>#define SDHCI_MAKE_BLKSZ(blksz) (1 << 12) | (blksz & 0xFFF)?



>



>



>> +



>> +		sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);



>> +



>> +		mmc_send_cmd(mmc, &cmd, NULL);



>> +



>> +		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 = -1;



>> +	}



>> +



>> +	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, SDHCI_INT_ENABLE);



>> +	/* Mask all sdhci interrupt sources */



>> +	sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);



>> +



>> +	return 0;



>



>Doesn't need to return "ret" when it's failed?



>



>> +}



>> +



>> +static struct sdhci_ops rockchip_sdhci_ops = {



>> +	.set_ios_post	= rockchip_sdhci_set_ios_post,



>> +	.platform_execute_tuning = &rockchip_sdhci_execute_tuning,



>>  };



>>  



>> -static int arasan_sdhci_probe(struct udevice *dev)



>> +static int rockchip_sdhci_probe(struct udevice *dev)



>>  {



>> +	struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(dev);



>>  	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);



>>  	struct rockchip_sdhc_plat *plat = dev_get_plat(dev);



>>  	struct rockchip_sdhc *prv = dev_get_priv(dev);



>> +	struct mmc_config *cfg = &plat->cfg;



>>  	struct sdhci_host *host = &prv->host;



>> -	int max_frequency, ret;



>>  	struct clk clk;



>> +	int ret;



>>  



>> -#if CONFIG_IS_ENABLED(OF_PLATDATA)



>> -	struct dtd_rockchip_rk3399_sdhci_5_1 *dtplat = &plat->dtplat;



>> -



>> -	host->name = dev->name;



>> -	host->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);



>> -	max_frequency = dtplat->max_frequency;



>> -	ret = clk_get_by_driver_info(dev, dtplat->clocks, &clk);



>> -#else



>> -	max_frequency = dev_read_u32_default(dev, "max-frequency", 0);



>> +	host->max_clk = cfg->f_max;



>>  	ret = clk_get_by_index(dev, 0, &clk);



>> -#endif



>>  	if (!ret) {



>> -		ret = clk_set_rate(&clk, max_frequency);



>> +		ret = clk_set_rate(&clk, host->max_clk);



>>  		if (IS_ERR_VALUE(ret))



>>  			printf("%s clk set rate fail!\n", __func__);



>>  	} else {



>>  		printf("%s fail to get clk\n", __func__);



>>  	}



>>  



>> +	prv->emmc_clk = clk;



>> +	prv->dev = dev;



>> +	ret = data->get_phy(dev);



>



>Ditto. Check data->get_phy.



>



>> +	if (ret)



>> +		return ret;



>> +



>> +	ret = data->emmc_phy_init(dev);



>



>Ditto.



>



>Best Regards,



>Jaehoon Chung



>



>> +	if (ret)



>> +		return ret;



>> +



>> +	host->ops = &rockchip_sdhci_ops;



>> +



>>  	host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;



>> -	host->max_clk = max_frequency;



>> -	/*



>> -	 * The sdhci-driver only supports 4bit and 8bit, as sdhci_setup_cfg



>> -	 * doesn't allow us to clear MMC_MODE_4BIT.  Consequently, we don't



>> -	 * check for other bus-width values.



>> -	 */



>> -	if (host->bus_width == 8)



>> -		host->host_caps |= MMC_MODE_8BIT;



>>  



>>  	host->mmc = &plat->mmc;



>>  	host->mmc->priv = &prv->host;



>>  	host->mmc->dev = dev;



>>  	upriv->mmc = host->mmc;



>>  



>> -	ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ);



>> +	ret = sdhci_setup_cfg(cfg, host, cfg->f_max, EMMC_MIN_FREQ);



>>  	if (ret)



>>  		return ret;



>>  



>>  	return sdhci_probe(dev);



>>  }



>>  



>> -static int arasan_sdhci_of_to_plat(struct udevice *dev)



>> +static int rockchip_sdhci_of_to_plat(struct udevice *dev)



>>  {



>> -#if !CONFIG_IS_ENABLED(OF_PLATDATA)



>> +	struct rockchip_sdhc_plat *plat = dev_get_plat(dev);



>>  	struct sdhci_host *host = dev_get_priv(dev);



>> +	struct mmc_config *cfg = &plat->cfg;



>> +	int ret;



>>  



>>  	host->name = dev->name;



>>  	host->ioaddr = dev_read_addr_ptr(dev);



>> -	host->bus_width = dev_read_u32_default(dev, "bus-width", 4);



>> -#endif



>> +



>> +	ret = mmc_of_parse(dev, cfg);



>> +	if (ret)



>> +		return ret;



>>  



>>  	return 0;



>>  }



>> @@ -101,19 +330,28 @@ static int rockchip_sdhci_bind(struct udevice *dev)



>>  	return sdhci_bind(dev, &plat->mmc, &plat->cfg);



>>  }



>>  



>> -static const struct udevice_id arasan_sdhci_ids[] = {



>> -	{ .compatible = "arasan,sdhci-5.1" },



>> +static const struct sdhci_data rk3399_data = {



>> +	.emmc_set_clock = rk3399_sdhci_emmc_set_clock,



>> +	.get_phy = rk3399_emmc_get_phy,



>> +	.emmc_phy_init = rk3399_emmc_phy_init,



>> +};



>> +



>> +static const struct udevice_id sdhci_ids[] = {



>> +	{



>> +		.compatible = "arasan,sdhci-5.1",



>> +		.data = (ulong)&rk3399_data,



>> +	},



>>  	{ }



>>  };



>>  



>>  U_BOOT_DRIVER(arasan_sdhci_drv) = {



>> -	.name		= "rockchip_rk3399_sdhci_5_1",



>> +	.name		= "rockchip_sdhci_5_1",



>>  	.id		= UCLASS_MMC,



>> -	.of_match	= arasan_sdhci_ids,



>> -	.of_to_plat = arasan_sdhci_of_to_plat,



>> +	.of_match	= sdhci_ids,



>> +	.of_to_plat	= rockchip_sdhci_of_to_plat,



>>  	.ops		= &sdhci_ops,



>>  	.bind		= rockchip_sdhci_bind,



>> -	.probe		= arasan_sdhci_probe,



>> +	.probe		= rockchip_sdhci_probe,



>>  	.priv_auto	= sizeof(struct rockchip_sdhc),



>>  	.plat_auto	= sizeof(struct rockchip_sdhc_plat),



>>  };



>> 



>



>



>



>



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399
  2021-06-28  9:19 ` [PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399 Yifeng Zhao
  2021-06-29  0:40   ` Jaehoon Chung
@ 2021-06-30  1:08   ` Peng Fan (OSS)
  2021-06-30  1:11   ` Peng Fan (OSS)
  2 siblings, 0 replies; 14+ messages in thread
From: Peng Fan (OSS) @ 2021-06-30  1:08 UTC (permalink / raw)
  To: Yifeng Zhao, Jaehoon Chung, sjg, Kever Yang
  Cc: Peng Fan, Philipp Tomsich, u-boot


On 2021/6/28 17:19, 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 <yifeng.zhao@rock-chips.com>
> ---
> 
> 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 | 310 +++++++++++++++++++++++++++++++----
>   1 file changed, 274 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
> index d95f8b2a15..2973911446 100644
> --- a/drivers/mmc/rockchip_sdhci.c
> +++ b/drivers/mmc/rockchip_sdhci.c
> @@ -6,90 +6,319 @@
>    */
>   
>   #include <common.h>
> +#include <clk.h>
>   #include <dm.h>
> +#include <dm/ofnode.h>
>   #include <dt-structs.h>
> +#include <linux/delay.h>
>   #include <linux/err.h>
>   #include <linux/libfdt.h>
> +#include <linux/iopoll.h>
>   #include <malloc.h>
>   #include <mapmem.h>
> +#include "mmc_private.h"
>   #include <sdhci.h>
> -#include <clk.h>
> +#include <syscon.h>
> +#include <asm/arch-rockchip/clock.h>
> +#include <asm/arch-rockchip/hardware.h>
>   
>   /* 400KHz is max freq for card ID etc. Use that as min */
>   #define EMMC_MIN_FREQ	400000
> +#define KHz	(1000)
> +#define MHz	(1000 * KHz)
> +#define SDHCI_TUNING_LOOP_COUNT		40
> +
> +#define PHYCTRL_CALDONE_MASK		0x1
> +#define PHYCTRL_CALDONE_SHIFT		0x6
> +#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

Please explain why remove this?

>   	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), &phy->emmcphy_con[6]);
> +	writel(RK_CLRSETBITS(1 << 11, 1 << 11), &phy->emmcphy_con[0]);
> +	writel(RK_CLRSETBITS(0xf << 7, 6 << 7), &phy->emmcphy_con[0]);

Would clrsetbits_le32 work?

> +
> +	/*
> +	 * 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), &phy->emmcphy_con[6]);

Ditto.

Regards,
Peng.
> +
> +	/*
> +	 * 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(&phy->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), &phy->emmcphy_con[0]);
> +	writel(RK_CLRSETBITS(1 << 1, 1 << 1), &phy->emmcphy_con[6]);

Ditto.

> +
> +	read_poll_timeout(readl, &phy->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), &phy->emmcphy_con[6]);
> +	writel(RK_CLRSETBITS(1 << 1, 0), &phy->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;
> +
> +	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;
> +	}
> +
> +	grf_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
> +	if (grf_base < 0)
> +		printf("%s Get syscon grf failed", __func__);
> +	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;
> +	int max_clk = host->max_clk;
> +	unsigned long mmc_clock;
> +
> +	if (cycle_phy)
> +		rk3399_emmc_phy_power_off(priv->phy);
> +
> +	if (clock) {
> +		mmc_clock = clk_set_rate(&priv->emmc_clk, clock);
> +		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;
> +
> +	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;
> +	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;
> +	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);
> +
> +	do {
> +		cmd.cmdidx = opcode;
> +		cmd.resp_type = MMC_RSP_R1;
> +		cmd.cmdarg = 0;
> +
> +		if (tuning_loop_counter-- == 0)
> +			break;
> +
> +		if (opcode == MMC_CMD_SEND_TUNING_BLOCK_HS200 && host->mmc->bus_width == 8)
> +			sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128), SDHCI_BLOCK_SIZE);
> +		else
> +			sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE);
> +
> +		sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
> +
> +		mmc_send_cmd(mmc, &cmd, NULL);
> +
> +		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 = -1;
> +	}
> +
> +	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, SDHCI_INT_ENABLE);
> +	/* Mask all sdhci interrupt sources */
> +	sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);
> +
> +	return 0;
> +}
> +
> +static struct sdhci_ops rockchip_sdhci_ops = {
> +	.set_ios_post	= rockchip_sdhci_set_ios_post,
> +	.platform_execute_tuning = &rockchip_sdhci_execute_tuning,
>   };
>   
> -static int arasan_sdhci_probe(struct udevice *dev)
> +static int rockchip_sdhci_probe(struct udevice *dev)
>   {
> +	struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(dev);
>   	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
>   	struct rockchip_sdhc_plat *plat = dev_get_plat(dev);
>   	struct rockchip_sdhc *prv = dev_get_priv(dev);
> +	struct mmc_config *cfg = &plat->cfg;
>   	struct sdhci_host *host = &prv->host;
> -	int max_frequency, ret;
>   	struct clk clk;
> +	int ret;
>   
> -#if CONFIG_IS_ENABLED(OF_PLATDATA)
> -	struct dtd_rockchip_rk3399_sdhci_5_1 *dtplat = &plat->dtplat;
> -
> -	host->name = dev->name;
> -	host->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
> -	max_frequency = dtplat->max_frequency;
> -	ret = clk_get_by_driver_info(dev, dtplat->clocks, &clk);
> -#else
> -	max_frequency = dev_read_u32_default(dev, "max-frequency", 0);
> +	host->max_clk = cfg->f_max;
>   	ret = clk_get_by_index(dev, 0, &clk);
> -#endif
>   	if (!ret) {
> -		ret = clk_set_rate(&clk, max_frequency);
> +		ret = clk_set_rate(&clk, host->max_clk);
>   		if (IS_ERR_VALUE(ret))
>   			printf("%s clk set rate fail!\n", __func__);
>   	} else {
>   		printf("%s fail to get clk\n", __func__);
>   	}
>   
> +	prv->emmc_clk = clk;
> +	prv->dev = dev;
> +	ret = data->get_phy(dev);
> +	if (ret)
> +		return ret;
> +
> +	ret = data->emmc_phy_init(dev);
> +	if (ret)
> +		return ret;
> +
> +	host->ops = &rockchip_sdhci_ops;
> +
>   	host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
> -	host->max_clk = max_frequency;
> -	/*
> -	 * The sdhci-driver only supports 4bit and 8bit, as sdhci_setup_cfg
> -	 * doesn't allow us to clear MMC_MODE_4BIT.  Consequently, we don't
> -	 * check for other bus-width values.
> -	 */
> -	if (host->bus_width == 8)
> -		host->host_caps |= MMC_MODE_8BIT;
>   
>   	host->mmc = &plat->mmc;
>   	host->mmc->priv = &prv->host;
>   	host->mmc->dev = dev;
>   	upriv->mmc = host->mmc;
>   
> -	ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ);
> +	ret = sdhci_setup_cfg(cfg, host, cfg->f_max, EMMC_MIN_FREQ);
>   	if (ret)
>   		return ret;
>   
>   	return sdhci_probe(dev);
>   }
>   
> -static int arasan_sdhci_of_to_plat(struct udevice *dev)
> +static int rockchip_sdhci_of_to_plat(struct udevice *dev)
>   {
> -#if !CONFIG_IS_ENABLED(OF_PLATDATA)
> +	struct rockchip_sdhc_plat *plat = dev_get_plat(dev);
>   	struct sdhci_host *host = dev_get_priv(dev);
> +	struct mmc_config *cfg = &plat->cfg;
> +	int ret;
>   
>   	host->name = dev->name;
>   	host->ioaddr = dev_read_addr_ptr(dev);
> -	host->bus_width = dev_read_u32_default(dev, "bus-width", 4);
> -#endif
> +
> +	ret = mmc_of_parse(dev, cfg);
> +	if (ret)
> +		return ret;
>   
>   	return 0;
>   }
> @@ -101,19 +330,28 @@ static int rockchip_sdhci_bind(struct udevice *dev)
>   	return sdhci_bind(dev, &plat->mmc, &plat->cfg);
>   }
>   
> -static const struct udevice_id arasan_sdhci_ids[] = {
> -	{ .compatible = "arasan,sdhci-5.1" },
> +static const struct sdhci_data rk3399_data = {
> +	.emmc_set_clock = rk3399_sdhci_emmc_set_clock,
> +	.get_phy = rk3399_emmc_get_phy,
> +	.emmc_phy_init = rk3399_emmc_phy_init,
> +};
> +
> +static const struct udevice_id sdhci_ids[] = {
> +	{
> +		.compatible = "arasan,sdhci-5.1",
> +		.data = (ulong)&rk3399_data,
> +	},
>   	{ }
>   };
>   
>   U_BOOT_DRIVER(arasan_sdhci_drv) = {
> -	.name		= "rockchip_rk3399_sdhci_5_1",
> +	.name		= "rockchip_sdhci_5_1",
>   	.id		= UCLASS_MMC,
> -	.of_match	= arasan_sdhci_ids,
> -	.of_to_plat = arasan_sdhci_of_to_plat,
> +	.of_match	= sdhci_ids,
> +	.of_to_plat	= rockchip_sdhci_of_to_plat,
>   	.ops		= &sdhci_ops,
>   	.bind		= rockchip_sdhci_bind,
> -	.probe		= arasan_sdhci_probe,
> +	.probe		= rockchip_sdhci_probe,
>   	.priv_auto	= sizeof(struct rockchip_sdhc),
>   	.plat_auto	= sizeof(struct rockchip_sdhc_plat),
>   };
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399
  2021-06-28  9:19 ` [PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399 Yifeng Zhao
  2021-06-29  0:40   ` Jaehoon Chung
  2021-06-30  1:08   ` Peng Fan (OSS)
@ 2021-06-30  1:11   ` Peng Fan (OSS)
  2 siblings, 0 replies; 14+ messages in thread
From: Peng Fan (OSS) @ 2021-06-30  1:11 UTC (permalink / raw)
  To: Yifeng Zhao, Jaehoon Chung, sjg, Kever Yang
  Cc: Peng Fan, Philipp Tomsich, u-boot



On 2021/6/28 17:19, 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.

One more generic question,
could phy part be moved to a phy driver?

Regards,
Peng.

> - 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 <yifeng.zhao@rock-chips.com>
> ---
> 
> 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 | 310 +++++++++++++++++++++++++++++++----
>   1 file changed, 274 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
> index d95f8b2a15..2973911446 100644
> --- a/drivers/mmc/rockchip_sdhci.c
> +++ b/drivers/mmc/rockchip_sdhci.c
> @@ -6,90 +6,319 @@
>    */
>   
>   #include <common.h>
> +#include <clk.h>
>   #include <dm.h>
> +#include <dm/ofnode.h>
>   #include <dt-structs.h>
> +#include <linux/delay.h>
>   #include <linux/err.h>
>   #include <linux/libfdt.h>
> +#include <linux/iopoll.h>
>   #include <malloc.h>
>   #include <mapmem.h>
> +#include "mmc_private.h"
>   #include <sdhci.h>
> -#include <clk.h>
> +#include <syscon.h>
> +#include <asm/arch-rockchip/clock.h>
> +#include <asm/arch-rockchip/hardware.h>
>   
>   /* 400KHz is max freq for card ID etc. Use that as min */
>   #define EMMC_MIN_FREQ	400000
> +#define KHz	(1000)
> +#define MHz	(1000 * KHz)
> +#define SDHCI_TUNING_LOOP_COUNT		40
> +
> +#define PHYCTRL_CALDONE_MASK		0x1
> +#define PHYCTRL_CALDONE_SHIFT		0x6
> +#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), &phy->emmcphy_con[6]);
> +	writel(RK_CLRSETBITS(1 << 11, 1 << 11), &phy->emmcphy_con[0]);
> +	writel(RK_CLRSETBITS(0xf << 7, 6 << 7), &phy->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), &phy->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(&phy->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), &phy->emmcphy_con[0]);
> +	writel(RK_CLRSETBITS(1 << 1, 1 << 1), &phy->emmcphy_con[6]);
> +
> +	read_poll_timeout(readl, &phy->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), &phy->emmcphy_con[6]);
> +	writel(RK_CLRSETBITS(1 << 1, 0), &phy->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;
> +
> +	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;
> +	}
> +
> +	grf_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
> +	if (grf_base < 0)
> +		printf("%s Get syscon grf failed", __func__);
> +	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;
> +	int max_clk = host->max_clk;
> +	unsigned long mmc_clock;
> +
> +	if (cycle_phy)
> +		rk3399_emmc_phy_power_off(priv->phy);
> +
> +	if (clock) {
> +		mmc_clock = clk_set_rate(&priv->emmc_clk, clock);
> +		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;
> +
> +	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;
> +	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;
> +	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);
> +
> +	do {
> +		cmd.cmdidx = opcode;
> +		cmd.resp_type = MMC_RSP_R1;
> +		cmd.cmdarg = 0;
> +
> +		if (tuning_loop_counter-- == 0)
> +			break;
> +
> +		if (opcode == MMC_CMD_SEND_TUNING_BLOCK_HS200 && host->mmc->bus_width == 8)
> +			sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128), SDHCI_BLOCK_SIZE);
> +		else
> +			sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE);
> +
> +		sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
> +
> +		mmc_send_cmd(mmc, &cmd, NULL);
> +
> +		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 = -1;
> +	}
> +
> +	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, SDHCI_INT_ENABLE);
> +	/* Mask all sdhci interrupt sources */
> +	sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);
> +
> +	return 0;
> +}
> +
> +static struct sdhci_ops rockchip_sdhci_ops = {
> +	.set_ios_post	= rockchip_sdhci_set_ios_post,
> +	.platform_execute_tuning = &rockchip_sdhci_execute_tuning,
>   };
>   
> -static int arasan_sdhci_probe(struct udevice *dev)
> +static int rockchip_sdhci_probe(struct udevice *dev)
>   {
> +	struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(dev);
>   	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
>   	struct rockchip_sdhc_plat *plat = dev_get_plat(dev);
>   	struct rockchip_sdhc *prv = dev_get_priv(dev);
> +	struct mmc_config *cfg = &plat->cfg;
>   	struct sdhci_host *host = &prv->host;
> -	int max_frequency, ret;
>   	struct clk clk;
> +	int ret;
>   
> -#if CONFIG_IS_ENABLED(OF_PLATDATA)
> -	struct dtd_rockchip_rk3399_sdhci_5_1 *dtplat = &plat->dtplat;
> -
> -	host->name = dev->name;
> -	host->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
> -	max_frequency = dtplat->max_frequency;
> -	ret = clk_get_by_driver_info(dev, dtplat->clocks, &clk);
> -#else
> -	max_frequency = dev_read_u32_default(dev, "max-frequency", 0);
> +	host->max_clk = cfg->f_max;
>   	ret = clk_get_by_index(dev, 0, &clk);
> -#endif
>   	if (!ret) {
> -		ret = clk_set_rate(&clk, max_frequency);
> +		ret = clk_set_rate(&clk, host->max_clk);
>   		if (IS_ERR_VALUE(ret))
>   			printf("%s clk set rate fail!\n", __func__);
>   	} else {
>   		printf("%s fail to get clk\n", __func__);
>   	}
>   
> +	prv->emmc_clk = clk;
> +	prv->dev = dev;
> +	ret = data->get_phy(dev);
> +	if (ret)
> +		return ret;
> +
> +	ret = data->emmc_phy_init(dev);
> +	if (ret)
> +		return ret;
> +
> +	host->ops = &rockchip_sdhci_ops;
> +
>   	host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
> -	host->max_clk = max_frequency;
> -	/*
> -	 * The sdhci-driver only supports 4bit and 8bit, as sdhci_setup_cfg
> -	 * doesn't allow us to clear MMC_MODE_4BIT.  Consequently, we don't
> -	 * check for other bus-width values.
> -	 */
> -	if (host->bus_width == 8)
> -		host->host_caps |= MMC_MODE_8BIT;
>   
>   	host->mmc = &plat->mmc;
>   	host->mmc->priv = &prv->host;
>   	host->mmc->dev = dev;
>   	upriv->mmc = host->mmc;
>   
> -	ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ);
> +	ret = sdhci_setup_cfg(cfg, host, cfg->f_max, EMMC_MIN_FREQ);
>   	if (ret)
>   		return ret;
>   
>   	return sdhci_probe(dev);
>   }
>   
> -static int arasan_sdhci_of_to_plat(struct udevice *dev)
> +static int rockchip_sdhci_of_to_plat(struct udevice *dev)
>   {
> -#if !CONFIG_IS_ENABLED(OF_PLATDATA)
> +	struct rockchip_sdhc_plat *plat = dev_get_plat(dev);
>   	struct sdhci_host *host = dev_get_priv(dev);
> +	struct mmc_config *cfg = &plat->cfg;
> +	int ret;
>   
>   	host->name = dev->name;
>   	host->ioaddr = dev_read_addr_ptr(dev);
> -	host->bus_width = dev_read_u32_default(dev, "bus-width", 4);
> -#endif
> +
> +	ret = mmc_of_parse(dev, cfg);
> +	if (ret)
> +		return ret;
>   
>   	return 0;
>   }
> @@ -101,19 +330,28 @@ static int rockchip_sdhci_bind(struct udevice *dev)
>   	return sdhci_bind(dev, &plat->mmc, &plat->cfg);
>   }
>   
> -static const struct udevice_id arasan_sdhci_ids[] = {
> -	{ .compatible = "arasan,sdhci-5.1" },
> +static const struct sdhci_data rk3399_data = {
> +	.emmc_set_clock = rk3399_sdhci_emmc_set_clock,
> +	.get_phy = rk3399_emmc_get_phy,
> +	.emmc_phy_init = rk3399_emmc_phy_init,
> +};
> +
> +static const struct udevice_id sdhci_ids[] = {
> +	{
> +		.compatible = "arasan,sdhci-5.1",
> +		.data = (ulong)&rk3399_data,
> +	},
>   	{ }
>   };
>   
>   U_BOOT_DRIVER(arasan_sdhci_drv) = {
> -	.name		= "rockchip_rk3399_sdhci_5_1",
> +	.name		= "rockchip_sdhci_5_1",
>   	.id		= UCLASS_MMC,
> -	.of_match	= arasan_sdhci_ids,
> -	.of_to_plat = arasan_sdhci_of_to_plat,
> +	.of_match	= sdhci_ids,
> +	.of_to_plat	= rockchip_sdhci_of_to_plat,
>   	.ops		= &sdhci_ops,
>   	.bind		= rockchip_sdhci_bind,
> -	.probe		= arasan_sdhci_probe,
> +	.probe		= rockchip_sdhci_probe,
>   	.priv_auto	= sizeof(struct rockchip_sdhc),
>   	.plat_auto	= sizeof(struct rockchip_sdhc_plat),
>   };
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2021-06-30  1:11 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-28  9:19 [PATCH v2 0/3] Yifeng Zhao
2021-06-28  9:19 ` [PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399 Yifeng Zhao
2021-06-29  0:40   ` Jaehoon Chung
2021-06-29  7:15     ` 赵仪峰
2021-06-30  1:08   ` Peng Fan (OSS)
2021-06-30  1:11   ` Peng Fan (OSS)
2021-06-28  9:19 ` [PATCH v2 2/3] mmc: rockchip_sdhci: Add support for RK3568 Yifeng Zhao
2021-06-29  0:45   ` Jaehoon Chung
2021-06-29  2:07     ` 赵仪峰
2021-06-29  3:18       ` Jaehoon Chung
2021-06-28  9:19 ` [PATCH v2 3/3] rockchip: config: evb-rk3399: add hs200 and hs400 support Yifeng Zhao
2021-06-28  9:21   ` Philipp Tomsich
2021-06-28  9:25 ` [PATCH v2 0/3] Philipp Tomsich
2021-06-28  9:32   ` Peter Robinson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.