diff mbox series

[v2,13/17] mmc: rockchip_sdhci: Add support for RK3588

Message ID 20230418164618.2571309-14-jonas@kwiboo.se
State Accepted
Commit a3cab289f6fcb8e014260d278913d20575f16811
Delegated to: Kever Yang
Headers show
Series rockchip: eMMC fixes for RK3568 and support for RK3588 | expand

Commit Message

Jonas Karlman April 18, 2023, 4:46 p.m. UTC
Add support for RK3588 to the rockchip sdhci driver.

Use driver data to handle differences between RK3568 and RK3588:

- Set "Receive original clock source is auto gating" for RK3588.
- Set "Receive clock source is no-inverted" only on RK3568 and "Transmit
  clock source is invertion of original clock input" for RK3588.
- Use different txclk_tapnum for HS400 modes on RK3588.
- Configure the CMDOUT reg for HS400 modes for RK3588.

This is based on the mainline linux and vendor kernel driver and have
successfully been tested with rock5b-rk3588_defconfig and

  CONFIG_MMC_HS200_SUPPORT=y
  CONFIG_MMC_HS400_SUPPORT=y
  CONFIG_MMC_HS400_ES_SUPPORT=y
  CONFIG_MMC_SPEED_MODE_SET=y

using the following command to switch mode and then read 512 MiB of data
from eMMC into memory,

  => mmc dev 0 0 <mode> && mmc info && mmc read 10000000 2000 10000

for each of the modes below.

  0 = MMC legacy
  1 = MMC High Speed (26MHz)
  3 = MMC High Speed (52MHz)
  4 = MMC DDR52 (52MHz)
  10 = HS200 (200MHz)
  11 = HS400 (200MHz)
  12 = HS400ES (200MHz)

Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
---
v2:
- Add Signed-off-by tag
- Update commit message
- Rename quirks to flags
- Save HS200/HS400 txclk_tapnum as driver data
- Remove use of rockchip,txclk-tapnum prop
- Collect r-b tag

 drivers/mmc/rockchip_sdhci.c | 57 +++++++++++++++++++++++++++++++++---
 1 file changed, 53 insertions(+), 4 deletions(-)

Comments

Kever Yang April 20, 2023, 10:03 a.m. UTC | #1
On 2023/4/19 00:46, Jonas Karlman wrote:
> Add support for RK3588 to the rockchip sdhci driver.
>
> Use driver data to handle differences between RK3568 and RK3588:
>
> - Set "Receive original clock source is auto gating" for RK3588.
> - Set "Receive clock source is no-inverted" only on RK3568 and "Transmit
>    clock source is invertion of original clock input" for RK3588.
> - Use different txclk_tapnum for HS400 modes on RK3588.
> - Configure the CMDOUT reg for HS400 modes for RK3588.
>
> This is based on the mainline linux and vendor kernel driver and have
> successfully been tested with rock5b-rk3588_defconfig and
>
>    CONFIG_MMC_HS200_SUPPORT=y
>    CONFIG_MMC_HS400_SUPPORT=y
>    CONFIG_MMC_HS400_ES_SUPPORT=y
>    CONFIG_MMC_SPEED_MODE_SET=y
>
> using the following command to switch mode and then read 512 MiB of data
> from eMMC into memory,
>
>    => mmc dev 0 0 <mode> && mmc info && mmc read 10000000 2000 10000
>
> for each of the modes below.
>
>    0 = MMC legacy
>    1 = MMC High Speed (26MHz)
>    3 = MMC High Speed (52MHz)
>    4 = MMC DDR52 (52MHz)
>    10 = HS200 (200MHz)
>    11 = HS400 (200MHz)
>    12 = HS400ES (200MHz)
>
> Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
> Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
Reviewed-by: Kever Yang <kever.yang@rock-chips.com>

Thanks,
- Kever

> ---
> v2:
> - Add Signed-off-by tag
> - Update commit message
> - Rename quirks to flags
> - Save HS200/HS400 txclk_tapnum as driver data
> - Remove use of rockchip,txclk-tapnum prop
> - Collect r-b tag
>
>   drivers/mmc/rockchip_sdhci.c | 57 +++++++++++++++++++++++++++++++++---
>   1 file changed, 53 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
> index 12a616d3dfb8..2857dcc9ec4f 100644
> --- a/drivers/mmc/rockchip_sdhci.c
> +++ b/drivers/mmc/rockchip_sdhci.c
> @@ -56,6 +56,7 @@
>   #define DWCMSHC_EMMC_DLL_RXCLK		0x804
>   #define DWCMSHC_EMMC_DLL_TXCLK		0x808
>   #define DWCMSHC_EMMC_DLL_STRBIN		0x80c
> +#define DWCMSHC_EMMC_DLL_CMDOUT		0x810
>   #define DWCMSHC_EMMC_DLL_STATUS0	0x840
>   #define DWCMSHC_EMMC_DLL_STATUS1	0x844
>   #define DWCMSHC_EMMC_DLL_START		BIT(0)
> @@ -70,18 +71,27 @@
>   #define DLL_RXCLK_NO_INVERTER		BIT(29)
>   #define DLL_RXCLK_ORI_GATE		BIT(31)
>   #define DLL_TXCLK_TAPNUM_DEFAULT	0x10
> +#define DLL_TXCLK_TAPNUM_90_DEGREES	0x9
>   #define DLL_TXCLK_TAPNUM_FROM_SW	BIT(24)
> +#define DLL_TXCLK_NO_INVERTER		BIT(29)
>   #define DLL_STRBIN_TAPNUM_DEFAULT	0x4
>   #define DLL_STRBIN_TAPNUM_FROM_SW	BIT(24)
>   #define DLL_STRBIN_DELAY_NUM_SEL	BIT(26)
>   #define DLL_STRBIN_DELAY_NUM_OFFSET	16
>   #define DLL_STRBIN_DELAY_NUM_DEFAULT	0x10
> +#define DLL_CMDOUT_TAPNUM_90_DEGREES	0x8
> +#define DLL_CMDOUT_TAPNUM_FROM_SW	BIT(24)
> +#define DLL_CMDOUT_SRC_CLK_NEG		BIT(28)
> +#define DLL_CMDOUT_EN_SRC_CLK_NEG	BIT(29)
> +#define DLL_CMDOUT_BOTH_CLK_EDGE	BIT(30)
>   
>   #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
>   
> +#define FLAG_INVERTER_FLAG_IN_RXCLK	BIT(0)
> +
>   struct rockchip_sdhc_plat {
>   	struct mmc_config cfg;
>   	struct mmc mmc;
> @@ -144,6 +154,10 @@ struct sdhci_data {
>   	 * Return: 0 if successful, -ve on error
>   	 */
>   	int (*set_enhanced_strobe)(struct sdhci_host *host);
> +
> +	u32 flags;
> +	u8 hs200_txclk_tapnum;
> +	u8 hs400_txclk_tapnum;
>   };
>   
>   static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 clock)
> @@ -294,8 +308,11 @@ static void rk3568_sdhci_set_clock(struct sdhci_host *host, u32 div)
>   
>   static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enable)
>   {
> +	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;
>   	int val, ret;
> -	u32 extra;
> +	u32 extra, txclk_tapnum;
>   
>   	if (!enable)
>   		return 0;
> @@ -318,12 +335,28 @@ static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab
>   		if (ret)
>   			return ret;
>   
> -		extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_NO_INVERTER;
> +		extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_ORI_GATE;
> +		if (data->flags & FLAG_INVERTER_FLAG_IN_RXCLK)
> +			extra |= DLL_RXCLK_NO_INVERTER;
>   		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
>   
> +		txclk_tapnum = data->hs200_txclk_tapnum;
> +		if (mmc->selected_mode == MMC_HS_400 ||
> +		    mmc->selected_mode == MMC_HS_400_ES) {
> +			txclk_tapnum = data->hs400_txclk_tapnum;
> +
> +			extra = DLL_CMDOUT_SRC_CLK_NEG |
> +				DLL_CMDOUT_BOTH_CLK_EDGE |
> +				DWCMSHC_EMMC_DLL_DLYENA |
> +				DLL_CMDOUT_TAPNUM_90_DEGREES |
> +				DLL_CMDOUT_TAPNUM_FROM_SW;
> +			sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CMDOUT);
> +		}
> +
>   		extra = DWCMSHC_EMMC_DLL_DLYENA |
> -			DLL_TXCLK_TAPNUM_DEFAULT |
> -			DLL_TXCLK_TAPNUM_FROM_SW;
> +			DLL_TXCLK_TAPNUM_FROM_SW |
> +			DLL_TXCLK_NO_INVERTER |
> +			txclk_tapnum;
>   		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK);
>   
>   		extra = DWCMSHC_EMMC_DLL_DLYENA |
> @@ -339,6 +372,7 @@ static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab
>   		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CTRL);
>   		sdhci_writel(host, DLL_RXCLK_ORI_GATE, DWCMSHC_EMMC_DLL_RXCLK);
>   		sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
> +		sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CMDOUT);
>   		/*
>   		 * Before switching to hs400es mode, the driver will enable
>   		 * enhanced strobe first. PHY needs to configure the parameters
> @@ -594,6 +628,17 @@ static const struct sdhci_data rk3568_data = {
>   	.set_ios_post = rk3568_sdhci_set_ios_post,
>   	.set_clock = rk3568_sdhci_set_clock,
>   	.config_dll = rk3568_sdhci_config_dll,
> +	.flags = FLAG_INVERTER_FLAG_IN_RXCLK,
> +	.hs200_txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT,
> +	.hs400_txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT,
> +};
> +
> +static const struct sdhci_data rk3588_data = {
> +	.set_ios_post = rk3568_sdhci_set_ios_post,
> +	.set_clock = rk3568_sdhci_set_clock,
> +	.config_dll = rk3568_sdhci_config_dll,
> +	.hs200_txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT,
> +	.hs400_txclk_tapnum = DLL_TXCLK_TAPNUM_90_DEGREES,
>   };
>   
>   static const struct udevice_id sdhci_ids[] = {
> @@ -605,6 +650,10 @@ static const struct udevice_id sdhci_ids[] = {
>   		.compatible = "rockchip,rk3568-dwcmshc",
>   		.data = (ulong)&rk3568_data,
>   	},
> +	{
> +		.compatible = "rockchip,rk3588-dwcmshc",
> +		.data = (ulong)&rk3588_data,
> +	},
>   	{ }
>   };
>
diff mbox series

Patch

diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
index 12a616d3dfb8..2857dcc9ec4f 100644
--- a/drivers/mmc/rockchip_sdhci.c
+++ b/drivers/mmc/rockchip_sdhci.c
@@ -56,6 +56,7 @@ 
 #define DWCMSHC_EMMC_DLL_RXCLK		0x804
 #define DWCMSHC_EMMC_DLL_TXCLK		0x808
 #define DWCMSHC_EMMC_DLL_STRBIN		0x80c
+#define DWCMSHC_EMMC_DLL_CMDOUT		0x810
 #define DWCMSHC_EMMC_DLL_STATUS0	0x840
 #define DWCMSHC_EMMC_DLL_STATUS1	0x844
 #define DWCMSHC_EMMC_DLL_START		BIT(0)
@@ -70,18 +71,27 @@ 
 #define DLL_RXCLK_NO_INVERTER		BIT(29)
 #define DLL_RXCLK_ORI_GATE		BIT(31)
 #define DLL_TXCLK_TAPNUM_DEFAULT	0x10
+#define DLL_TXCLK_TAPNUM_90_DEGREES	0x9
 #define DLL_TXCLK_TAPNUM_FROM_SW	BIT(24)
+#define DLL_TXCLK_NO_INVERTER		BIT(29)
 #define DLL_STRBIN_TAPNUM_DEFAULT	0x4
 #define DLL_STRBIN_TAPNUM_FROM_SW	BIT(24)
 #define DLL_STRBIN_DELAY_NUM_SEL	BIT(26)
 #define DLL_STRBIN_DELAY_NUM_OFFSET	16
 #define DLL_STRBIN_DELAY_NUM_DEFAULT	0x10
+#define DLL_CMDOUT_TAPNUM_90_DEGREES	0x8
+#define DLL_CMDOUT_TAPNUM_FROM_SW	BIT(24)
+#define DLL_CMDOUT_SRC_CLK_NEG		BIT(28)
+#define DLL_CMDOUT_EN_SRC_CLK_NEG	BIT(29)
+#define DLL_CMDOUT_BOTH_CLK_EDGE	BIT(30)
 
 #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
 
+#define FLAG_INVERTER_FLAG_IN_RXCLK	BIT(0)
+
 struct rockchip_sdhc_plat {
 	struct mmc_config cfg;
 	struct mmc mmc;
@@ -144,6 +154,10 @@  struct sdhci_data {
 	 * Return: 0 if successful, -ve on error
 	 */
 	int (*set_enhanced_strobe)(struct sdhci_host *host);
+
+	u32 flags;
+	u8 hs200_txclk_tapnum;
+	u8 hs400_txclk_tapnum;
 };
 
 static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 clock)
@@ -294,8 +308,11 @@  static void rk3568_sdhci_set_clock(struct sdhci_host *host, u32 div)
 
 static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enable)
 {
+	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;
 	int val, ret;
-	u32 extra;
+	u32 extra, txclk_tapnum;
 
 	if (!enable)
 		return 0;
@@ -318,12 +335,28 @@  static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab
 		if (ret)
 			return ret;
 
-		extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_NO_INVERTER;
+		extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_ORI_GATE;
+		if (data->flags & FLAG_INVERTER_FLAG_IN_RXCLK)
+			extra |= DLL_RXCLK_NO_INVERTER;
 		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
 
+		txclk_tapnum = data->hs200_txclk_tapnum;
+		if (mmc->selected_mode == MMC_HS_400 ||
+		    mmc->selected_mode == MMC_HS_400_ES) {
+			txclk_tapnum = data->hs400_txclk_tapnum;
+
+			extra = DLL_CMDOUT_SRC_CLK_NEG |
+				DLL_CMDOUT_BOTH_CLK_EDGE |
+				DWCMSHC_EMMC_DLL_DLYENA |
+				DLL_CMDOUT_TAPNUM_90_DEGREES |
+				DLL_CMDOUT_TAPNUM_FROM_SW;
+			sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CMDOUT);
+		}
+
 		extra = DWCMSHC_EMMC_DLL_DLYENA |
-			DLL_TXCLK_TAPNUM_DEFAULT |
-			DLL_TXCLK_TAPNUM_FROM_SW;
+			DLL_TXCLK_TAPNUM_FROM_SW |
+			DLL_TXCLK_NO_INVERTER |
+			txclk_tapnum;
 		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK);
 
 		extra = DWCMSHC_EMMC_DLL_DLYENA |
@@ -339,6 +372,7 @@  static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab
 		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CTRL);
 		sdhci_writel(host, DLL_RXCLK_ORI_GATE, DWCMSHC_EMMC_DLL_RXCLK);
 		sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
+		sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CMDOUT);
 		/*
 		 * Before switching to hs400es mode, the driver will enable
 		 * enhanced strobe first. PHY needs to configure the parameters
@@ -594,6 +628,17 @@  static const struct sdhci_data rk3568_data = {
 	.set_ios_post = rk3568_sdhci_set_ios_post,
 	.set_clock = rk3568_sdhci_set_clock,
 	.config_dll = rk3568_sdhci_config_dll,
+	.flags = FLAG_INVERTER_FLAG_IN_RXCLK,
+	.hs200_txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT,
+	.hs400_txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT,
+};
+
+static const struct sdhci_data rk3588_data = {
+	.set_ios_post = rk3568_sdhci_set_ios_post,
+	.set_clock = rk3568_sdhci_set_clock,
+	.config_dll = rk3568_sdhci_config_dll,
+	.hs200_txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT,
+	.hs400_txclk_tapnum = DLL_TXCLK_TAPNUM_90_DEGREES,
 };
 
 static const struct udevice_id sdhci_ids[] = {
@@ -605,6 +650,10 @@  static const struct udevice_id sdhci_ids[] = {
 		.compatible = "rockchip,rk3568-dwcmshc",
 		.data = (ulong)&rk3568_data,
 	},
+	{
+		.compatible = "rockchip,rk3588-dwcmshc",
+		.data = (ulong)&rk3588_data,
+	},
 	{ }
 };