[RFC,4/4] mmc: sdhci-of-dwcmshc: Add support for T-Head TH1520

Message ID 20230724-th1520-emmc-v1-4-cca1b2533da2@baylibre.com
State New
Headers
Series RISC-V: Add basic eMMC support for BeagleV Ahead |

Commit Message

Drew Fustini July 25, 2023, 12:59 a.m. UTC
  Add basic support for the T-Head TH1520 SoC mmc controller. The new
compatible "thead,th1520-dwcmshc" enables basic support by:

 - Enabling v4 mode to properly communicate with the mmc device
 - Setting quirk to disable ADMA
 - Setting flag to disable SDMA and force PIO mode
 - Turing .reset op into a no-op as the driver does not yet know how to
   configure the phy. Rely on the vendor u-boot to have configured the
   phy and do not reset the controller in Linux.

Signed-off-by: Drew Fustini <dfustini@baylibre.com>
---
 drivers/mmc/host/sdhci-of-dwcmshc.c | 42 +++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)
  

Comments

Jisheng Zhang July 25, 2023, 3:03 p.m. UTC | #1
On Mon, Jul 24, 2023 at 05:59:18PM -0700, Drew Fustini wrote:
> Add basic support for the T-Head TH1520 SoC mmc controller. The new
> compatible "thead,th1520-dwcmshc" enables basic support by:

Hi Drew,

> 
>  - Enabling v4 mode to properly communicate with the mmc device
>  - Setting quirk to disable ADMA
>  - Setting flag to disable SDMA and force PIO mode
>  - Turing .reset op into a no-op as the driver does not yet know how to
>    configure the phy. Rely on the vendor u-boot to have configured the
>    phy and do not reset the controller in Linux.

The last three itmes are not acceptable. The controller supports ADMA
well, can you plz bring in the phy driver? We can't rely on bootloader to
configure phy.

> 
> Signed-off-by: Drew Fustini <dfustini@baylibre.com>
> ---
>  drivers/mmc/host/sdhci-of-dwcmshc.c | 42 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 42 insertions(+)
> 
> diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c
> index e68cd87998c8..8573aff25a81 100644
> --- a/drivers/mmc/host/sdhci-of-dwcmshc.c
> +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
> @@ -337,6 +337,14 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask)
>  	sdhci_reset(host, mask);
>  }
>  
> +static void th1520_sdhci_reset(struct sdhci_host *host, u8 mask)
> +{
> +	/*
> +	 * MMC controller and phy is configured by vendor u-boot so
> +	 * take the simplistic approach of not doing reset in Linux.
> +	 */
> +}
> +
>  static const struct sdhci_ops sdhci_dwcmshc_ops = {
>  	.set_clock		= sdhci_set_clock,
>  	.set_bus_width		= sdhci_set_bus_width,
> @@ -355,6 +363,15 @@ static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = {
>  	.adma_write_desc	= dwcmshc_adma_write_desc,
>  };
>  
> +static const struct sdhci_ops sdhci_dwcmshc_th1520_ops = {
> +	.set_clock		= sdhci_set_clock,
> +	.set_bus_width		= sdhci_set_bus_width,
> +	.set_uhs_signaling	= dwcmshc_set_uhs_signaling,
> +	.get_max_clock		= dwcmshc_get_max_clock,
> +	.reset			= th1520_sdhci_reset,
> +	.adma_write_desc	= dwcmshc_adma_write_desc,
> +};
> +
>  static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
>  	.ops = &sdhci_dwcmshc_ops,
>  	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
> @@ -378,6 +395,13 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = {
>  		   SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
>  };
>  
> +static const struct sdhci_pltfm_data sdhci_dwcmshc_th1520_pdata = {
> +	.ops = &sdhci_dwcmshc_th1520_ops,
> +	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | SDHCI_QUIRK_BROKEN_DMA |
> +		  SDHCI_QUIRK_BROKEN_ADMA,
> +	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
> +};
> +
>  static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
>  {
>  	int err;
> @@ -434,6 +458,10 @@ static void dwcmshc_rk35xx_postinit(struct sdhci_host *host, struct dwcmshc_priv
>  }
>  
>  static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
> +	{
> +		.compatible = "thead,th1520-dwcmshc",
> +		.data = &sdhci_dwcmshc_th1520_pdata,
> +	},
>  	{
>  		.compatible = "rockchip,rk3588-dwcmshc",
>  		.data = &sdhci_dwcmshc_rk35xx_pdata,
> @@ -546,6 +574,20 @@ static int dwcmshc_probe(struct platform_device *pdev)
>  		sdhci_enable_v4_mode(host);
>  #endif
>  
> +	if (pltfm_data == &sdhci_dwcmshc_th1520_pdata) {
> +		/*
> +		 * The controller needs v4 mode enabled to properly
> +		 * communicate with the mmc device.
> +		 */
> +		sdhci_enable_v4_mode(host);
> +
> +		/*
> +		 * Set flag so the SDHCI host core will disable DMA
> +		 * and use PIO mode.
> +		 */
> +		host->flags &= ~SDHCI_USE_SDMA;
> +	}
> +
>  	host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
>  
>  	err = sdhci_setup_host(host);
> 
> -- 
> 2.34.1
>
  
Drew Fustini July 25, 2023, 3:54 p.m. UTC | #2
On Tue, Jul 25, 2023 at 11:03:44PM +0800, Jisheng Zhang wrote:
> On Mon, Jul 24, 2023 at 05:59:18PM -0700, Drew Fustini wrote:
> > Add basic support for the T-Head TH1520 SoC mmc controller. The new
> > compatible "thead,th1520-dwcmshc" enables basic support by:
> 
> Hi Drew,
> 
> > 
> >  - Enabling v4 mode to properly communicate with the mmc device
> >  - Setting quirk to disable ADMA
> >  - Setting flag to disable SDMA and force PIO mode
> >  - Turing .reset op into a no-op as the driver does not yet know how to
> >    configure the phy. Rely on the vendor u-boot to have configured the
> >    phy and do not reset the controller in Linux.
> 
> The last three itmes are not acceptable. The controller supports ADMA
> well, can you plz bring in the phy driver? We can't rely on bootloader to
> configure phy.

Yes, that makes sense that this is not acceptable. The T-Head vendor
kernel seems to contain all the necessary information needed to add the
phy configuration to sdhci-of-dwcmshc.

The shipping kernel for the BeagleV Ahead [1] is based on the T-Head SDK
releases. I looked at changes to drivers/mmc and found that key changes
are from Linux_SDK_V0.9.5 [2] and Linux_SDK_V1.0.2 [3].

That kernel contains drivers/mmc/host/sdhci-of-dwcmshc.h [4] which seems
to define information about the phy registers. The version of
drivers/mmc/host/sdhci-of-dwcmshc.h in that kernel defines several
functions for the phy config and controller reset:

sdhci_phy_1_8v_init_no_pull
sdhci_phy_3_3v_init_no_pull
snps_phy_1_8v_init
snps_phy_3_3v_init
snps_sdhci_set_phy
snps_sdhci_reset

I'll look into adapting that code into the upstream sdhci-of-dwcmshc.

Thanks,
Drew

[1] https://git.beagleboard.org/beaglev-ahead/beaglev-ahead-linux
[2] https://gist.github.com/pdp7/8d85d736dea24957c017eefdeb882668
[3] https://gist.github.com/pdp7/c1d3a18f9b7c25e630573d5953a58c99
[4] https://git.beagleboard.org/beaglev-ahead/beaglev-ahead-linux/-/blob/beaglev-v5.10.113-1.1.2/drivers/mmc/host/sdhci-of-dwcmshc.h
[5] https://git.beagleboard.org/beaglev-ahead/beaglev-ahead-linux/-/blob/beaglev-v5.10.113-1.1.2/drivers/mmc/host/sdhci-of-dwcmshc.c
  

Patch

diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c
index e68cd87998c8..8573aff25a81 100644
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
@@ -337,6 +337,14 @@  static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask)
 	sdhci_reset(host, mask);
 }
 
+static void th1520_sdhci_reset(struct sdhci_host *host, u8 mask)
+{
+	/*
+	 * MMC controller and phy is configured by vendor u-boot so
+	 * take the simplistic approach of not doing reset in Linux.
+	 */
+}
+
 static const struct sdhci_ops sdhci_dwcmshc_ops = {
 	.set_clock		= sdhci_set_clock,
 	.set_bus_width		= sdhci_set_bus_width,
@@ -355,6 +363,15 @@  static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = {
 	.adma_write_desc	= dwcmshc_adma_write_desc,
 };
 
+static const struct sdhci_ops sdhci_dwcmshc_th1520_ops = {
+	.set_clock		= sdhci_set_clock,
+	.set_bus_width		= sdhci_set_bus_width,
+	.set_uhs_signaling	= dwcmshc_set_uhs_signaling,
+	.get_max_clock		= dwcmshc_get_max_clock,
+	.reset			= th1520_sdhci_reset,
+	.adma_write_desc	= dwcmshc_adma_write_desc,
+};
+
 static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
 	.ops = &sdhci_dwcmshc_ops,
 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
@@ -378,6 +395,13 @@  static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = {
 		   SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
 };
 
+static const struct sdhci_pltfm_data sdhci_dwcmshc_th1520_pdata = {
+	.ops = &sdhci_dwcmshc_th1520_ops,
+	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | SDHCI_QUIRK_BROKEN_DMA |
+		  SDHCI_QUIRK_BROKEN_ADMA,
+	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+};
+
 static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
 {
 	int err;
@@ -434,6 +458,10 @@  static void dwcmshc_rk35xx_postinit(struct sdhci_host *host, struct dwcmshc_priv
 }
 
 static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
+	{
+		.compatible = "thead,th1520-dwcmshc",
+		.data = &sdhci_dwcmshc_th1520_pdata,
+	},
 	{
 		.compatible = "rockchip,rk3588-dwcmshc",
 		.data = &sdhci_dwcmshc_rk35xx_pdata,
@@ -546,6 +574,20 @@  static int dwcmshc_probe(struct platform_device *pdev)
 		sdhci_enable_v4_mode(host);
 #endif
 
+	if (pltfm_data == &sdhci_dwcmshc_th1520_pdata) {
+		/*
+		 * The controller needs v4 mode enabled to properly
+		 * communicate with the mmc device.
+		 */
+		sdhci_enable_v4_mode(host);
+
+		/*
+		 * Set flag so the SDHCI host core will disable DMA
+		 * and use PIO mode.
+		 */
+		host->flags &= ~SDHCI_USE_SDMA;
+	}
+
 	host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
 
 	err = sdhci_setup_host(host);