mmc: sdhci-of-dwcmshc: Add Sophgo SG2042 support
Subsystems (5)
v4 cover mmc: sdhci-of-dwcmshc: Add Sophgo SG2042 support
From: Chen Wang <[email protected]>
This patchset is composed of two parts:
- one is the improvement of the sdhci-of-dwcmshc framework,
- the other is the support for sg2042 based on the improvement of the framework.
The reason for merging the two parts into one patchset is mainly to facilitate review, especially to facilitate viewing why we need to improve the framework and what benefits it will bring to us.
When I tried to add a new soc(SG2042) to sdhci-of-dwcmshc, I found that the existing driver code could be optimized to facilitate expansion for the new soc. Patch 1 "mmc: sdhci-of-dwcmshc: add callback functions for dwcmshc" is for this.
Patch 2 ~ 3 are adding support for the mmc controller for Sophgo SG2042. Adding corresponding new compatible strings, and implement custom callbacks for SG2042 based on new framework.
Patch 4 is the change for DTS.
By the way, although I believe this patch only optimizes the framework of the code and does not change the specific logic, simple verification is certainly better. Since I don't have rk35xx/th1520 related hardware, it would be greatly appreciated if someone could help verify it. Note, the DTS change has dependency on clock changes for SG2042, which has not been merged in master/upstream, so if you want to test this new sdhci-of-dwcmshc driver for other hardware except SG2042, don't pick patch 4.
---
Changes in v4:
The patch series is based on latest 'next' branch of [mmc-git].
Improved the dirvier code as per comments from Adrian Hunter, drop moving position and renaming for some helper functions.
Put the sg2042 support as part of this series, improve the bindings and code as per comments from last review.
Changes in v3:
The patch series is based on latest 'next' branch of [mmc-git]. You can simply review or test the patches at the link [3].
Improved the dirvier code as per comments from Adrian Hunter. Define new structure for dwcmshc platform data/ops. In addition, I organized the code and classified the helper functions.
Since the file changes were relatively large (though the functional logic did not change much), I split the original patch into four for the convenience of review.
Changes in v2:
Rebased on latest 'next' branch of [mmc-git]. You can simply review or test the patches at the link [2].
Changes in v1:
The patch series is based on v6.9-rc1. You can simply review or test the patches at the link [1].
---
Chen Wang (4):
mmc: sdhci-of-dwcmshc: add callback functions for dwcmshc
dt-bindings: mmc: sdhci-of-dwcmhsc: Add Sophgo SG2042 support
mmc: sdhci-of-dwcmshc: Add support for Sophgo SG2042
riscv: dts: add mmc controllers for Sophgo SG2042 SoC
.../bindings/mmc/snps,dwcmshc-sdhci.yaml | 69 ++- .../boot/dts/sophgo/sg2042-milkv-pioneer.dts | 17 + arch/riscv/boot/dts/sophgo/sg2042.dtsi | 32 ++ drivers/mmc/host/sdhci-of-dwcmshc.c | 499 ++++++++++++------ 4 files changed, 447 insertions(+), 170 deletions(-)
base-commit: d6cd1206ffaaa890e81f5d1134856d9edd406ec6
Signature · 1 line
2.25.1
PATCH v4 1/4 mmc: sdhci-of-dwcmshc: add callback functions for dwcmshc
From: Chen Wang <[email protected]>
The current framework is not easily extended to support new SOCs. For example, in the current code we see that the SOC-level structure rk35xx_priv and related logic are distributed in functions such as dwcmshc_probe/dwcmshc_remove/dwcmshc_suspend/......, which is inappropriate.
The solution is to abstract some possible common operations of soc as dwcmshc platform data. Each soc implements the corresponding callback function according to its own needs.
dwcmshc framework is responsible for calling these callback functions in those dwcmshc_xxx functions at proper positions.
--- drivers/mmc/host/sdhci-of-dwcmshc.c | 327 ++++++++++++++++------------ 1 file changed, 184 insertions(+), 143 deletions(-)
drivers/mmc/host/sdhci-of-dwcmshc.c +184 -143
@@ -206,6 +206,7 @@ struct rk35xx_priv {u8 txclk_tapnum; }; +struct dwcmshc_pltfm_data ;struct dwcmshc_priv {struct clk *bus_clk;int vendor_specific_area1;/* P_VENDOR_SPECIFIC_AREA1 reg */
@@ -214,6 +215,16 @@ struct dwcmshc_priv {void *priv;/* pointer to SoC private stuff */ u16 delay_line;u16 flags; + +const struct dwcmshc_pltfm_data *pltfm_data; +}; + +struct dwcmshc_pltfm_data { +const struct sdhci_pltfm_data pdata; +int (*init)(struct device *dev,struct sdhci_host *host,struct dwcmshc_priv *dwc_priv); +void (*postinit)(struct sdhci_host *host,struct dwcmshc_priv *dwc_priv); +int (*clks_enable)(struct dwcmshc_priv *dwc_priv); +void (*clks_disable)(struct dwcmshc_priv *dwc_priv); };/*
@@ -681,6 +692,92 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask)sdhci_reset (host, mask); } +static int dwcmshc_rk35xx_init (struct device *dev,struct sdhci_host *host, +struct dwcmshc_priv *dwc_priv) +{ +int err; +struct rk35xx_priv *priv; + + priv =devm_kzalloc (dev,sizeof (struct rk35xx_priv ),GFP_KERNEL ); +if (!priv) +return -ENOMEM ; + +if (of_device_is_compatible (dev->of_node,"rockchip,rk3588-dwcmshc" )) + priv->devtype =DWCMSHC_RK3588 ; +else + priv->devtype =DWCMSHC_RK3568 ; + + priv->reset =devm_reset_control_array_get_optional_exclusive (mmc_dev (host->mmc)); +if (IS_ERR (priv->reset)) { + err =PTR_ERR (priv->reset); +dev_err (mmc_dev (host->mmc),"failed to get reset control %d\n" , err); +return err; + } + + priv->rockchip_clks[0 ].id ="axi" ; + priv->rockchip_clks[1 ].id ="block" ; + priv->rockchip_clks[2 ].id ="timer" ; + err =devm_clk_bulk_get_optional (mmc_dev (host->mmc), RK35xx_MAX_CLKS, + priv->rockchip_clks); +if (err) { +dev_err (mmc_dev (host->mmc),"failed to get clocks %d\n" , err); +return err; + } + + err =clk_bulk_prepare_enable (RK35xx_MAX_CLKS, priv->rockchip_clks); +if (err) { +dev_err (mmc_dev (host->mmc),"failed to enable clocks %d\n" , err); +return err; + } + +if (of_property_read_u8 (mmc_dev (host->mmc)->of_node,"rockchip,txclk-tapnum" , + &priv->txclk_tapnum)) + priv->txclk_tapnum =DLL_TXCLK_TAPNUM_DEFAULT ; + +/* Disable cmd conflict check */ +sdhci_writel (host,0x0 , dwc_priv->vendor_specific_area1 +DWCMSHC_HOST_CTRL3 ); +/* Reset previous settings */ +sdhci_writel (host,0 ,DWCMSHC_EMMC_DLL_TXCLK ); +sdhci_writel (host,0 ,DWCMSHC_EMMC_DLL_STRBIN ); + + dwc_priv->priv = priv; + +return 0 ; +} + +static void dwcmshc_rk35xx_postinit (struct sdhci_host *host,struct dwcmshc_priv *dwc_priv) +{ +/* +* Don't support highspeed bus mode with low clk speed as we +* cannot use DLL for this condition. +*/ +if (host->mmc->f_max <=52000000 ) { +dev_info (mmc_dev (host->mmc),"Disabling HS200/HS400, frequency too low (%d)\n" , + host->mmc->f_max); + host->mmc->caps2 &= ~(MMC_CAP2_HS200 |MMC_CAP2_HS400 ); + host->mmc->caps &= ~(MMC_CAP_3_3V_DDR |MMC_CAP_1_8V_DDR ); + } +} + +static int rk35xx_clks_enable (struct dwcmshc_priv *dwc_priv) +{ +struct rk35xx_priv *priv = dwc_priv->priv; +int ret =0 ; + +if (priv) + ret =clk_bulk_prepare_enable (RK35xx_MAX_CLKS, priv->rockchip_clks); +return ret; +} + +static void rk35xx_clks_disable (struct dwcmshc_priv *dwc_priv) +{ +struct rk35xx_priv *priv = dwc_priv->priv; + +if (priv) +clk_bulk_disable_unprepare (RK35xx_MAX_CLKS, + priv->rockchip_clks); +} +static int th1520_execute_tuning (struct sdhci_host *host,u32 opcode) {struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);
@@ -755,6 +852,35 @@ static void th1520_sdhci_reset(struct sdhci_host *host, u8 mask) } } +static int th1520_init (struct device *dev, +struct sdhci_host *host, +struct dwcmshc_priv *dwc_priv) +{ + dwc_priv->delay_line =PHY_SDCLKDL_DC_DEFAULT ; + +if (device_property_read_bool (dev,"mmc-ddr-1_8v" ) || +device_property_read_bool (dev,"mmc-hs200-1_8v" ) || +device_property_read_bool (dev,"mmc-hs400-1_8v" )) + dwc_priv->flags |=FLAG_IO_FIXED_1V8 ; +else + dwc_priv->flags &= ~FLAG_IO_FIXED_1V8 ; + +/* +* start_signal_voltage_switch() will try 3.3V first +* then 1.8V. Use SDHCI_SIGNALING_180 rather than +* SDHCI_SIGNALING_330 to avoid setting voltage to 3.3V +* in sdhci_start_signal_voltage_switch(). +*/ +if (dwc_priv->flags &FLAG_IO_FIXED_1V8 ) { + host->flags &= ~SDHCI_SIGNALING_330 ; + host->flags |=SDHCI_SIGNALING_180 ; + } + +sdhci_enable_v4_mode (host); + +return 0 ; +} +static void cv18xx_sdhci_reset (struct sdhci_host *host,u8 mask) {struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);
@@ -932,39 +1058,54 @@ static const struct sdhci_ops sdhci_dwcmshc_cv18xx_ops = { .platform_execute_tuning = cv18xx_sdhci_execute_tuning, }; -static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { - .ops = &sdhci_dwcmshc_ops, - .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , - .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN , +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_pdata = { + .pdata = { + .ops = &sdhci_dwcmshc_ops, + .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , + .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN , + }, };#ifdef CONFIG_ACPI -static const struct sdhci_pltfm_data sdhci_dwcmshc_bf3_pdata = { - .ops = &sdhci_dwcmshc_ops, - .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , - .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN | -SDHCI_QUIRK2_ACMD23_BROKEN , +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_bf3_pdata = { + .pdata = { + .ops = &sdhci_dwcmshc_ops, + .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , + .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN | +SDHCI_QUIRK2_ACMD23_BROKEN , + }, };#endif -static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = { - .ops = &sdhci_dwcmshc_rk35xx_ops, - .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | -SDHCI_QUIRK_BROKEN_TIMEOUT_VAL , - .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN | -SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN , +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_rk35xx_pdata = { + .pdata = { + .ops = &sdhci_dwcmshc_rk35xx_ops, + .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | +SDHCI_QUIRK_BROKEN_TIMEOUT_VAL , + .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN | +SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN , + }, + .init = dwcmshc_rk35xx_init, + .postinit = dwcmshc_rk35xx_postinit, + .clks_enable = rk35xx_clks_enable, + .clks_disable = rk35xx_clks_disable, }; -static const struct sdhci_pltfm_data sdhci_dwcmshc_th1520_pdata = { - .ops = &sdhci_dwcmshc_th1520_ops, - .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , - .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN , +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_th1520_pdata = { + .pdata = { + .ops = &sdhci_dwcmshc_th1520_ops, + .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , + .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN , + }, + .init = th1520_init, }; -static const struct sdhci_pltfm_data sdhci_dwcmshc_cv18xx_pdata = { - .ops = &sdhci_dwcmshc_cv18xx_ops, - .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , - .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN , +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_cv18xx_pdata = { + .pdata = { + .ops = &sdhci_dwcmshc_cv18xx_ops, + .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , + .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN , + }, };static const struct cqhci_host_ops dwcmshc_cqhci_ops = {
@@ -1034,61 +1175,6 @@ static void dwcmshc_cqhci_init(struct sdhci_host *host, struct platform_device * host->mmc->caps2 &= ~(MMC_CAP2_CQE |MMC_CAP2_CQE_DCMD ); } -static int dwcmshc_rk35xx_init (struct sdhci_host *host,struct dwcmshc_priv *dwc_priv) -{ -int err; -struct rk35xx_priv *priv = dwc_priv->priv; - - priv->reset =devm_reset_control_array_get_optional_exclusive (mmc_dev (host->mmc)); -if (IS_ERR (priv->reset)) { - err =PTR_ERR (priv->reset); -dev_err (mmc_dev (host->mmc),"failed to get reset control %d\n" , err); -return err; - } - - priv->rockchip_clks[0 ].id ="axi" ; - priv->rockchip_clks[1 ].id ="block" ; - priv->rockchip_clks[2 ].id ="timer" ; - err =devm_clk_bulk_get_optional (mmc_dev (host->mmc), RK35xx_MAX_CLKS, - priv->rockchip_clks); -if (err) { -dev_err (mmc_dev (host->mmc),"failed to get clocks %d\n" , err); -return err; - } - - err =clk_bulk_prepare_enable (RK35xx_MAX_CLKS, priv->rockchip_clks); -if (err) { -dev_err (mmc_dev (host->mmc),"failed to enable clocks %d\n" , err); -return err; - } - -if (of_property_read_u8 (mmc_dev (host->mmc)->of_node,"rockchip,txclk-tapnum" , - &priv->txclk_tapnum)) - priv->txclk_tapnum =DLL_TXCLK_TAPNUM_DEFAULT ; - -/* Disable cmd conflict check */ -sdhci_writel (host,0x0 , dwc_priv->vendor_specific_area1 +DWCMSHC_HOST_CTRL3 ); -/* Reset previous settings */ -sdhci_writel (host,0 ,DWCMSHC_EMMC_DLL_TXCLK ); -sdhci_writel (host,0 ,DWCMSHC_EMMC_DLL_STRBIN ); - -return 0 ; -} - -static void dwcmshc_rk35xx_postinit (struct sdhci_host *host,struct dwcmshc_priv *dwc_priv) -{ -/* -* Don't support highspeed bus mode with low clk speed as we -* cannot use DLL for this condition. -*/ -if (host->mmc->f_max <=52000000 ) { -dev_info (mmc_dev (host->mmc),"Disabling HS200/HS400, frequency too low (%d)\n" , - host->mmc->f_max); - host->mmc->caps2 &= ~(MMC_CAP2_HS200 |MMC_CAP2_HS400 ); - host->mmc->caps &= ~(MMC_CAP_3_3V_DDR |MMC_CAP_1_8V_DDR ); - } -} -static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { { .compatible ="rockchip,rk3588-dwcmshc" ,
@@ -1135,8 +1221,7 @@ static int dwcmshc_probe(struct platform_device *pdev)struct sdhci_pltfm_host *pltfm_host;struct sdhci_host *host;struct dwcmshc_priv *priv; -struct rk35xx_priv *rk_priv =NULL ; -const struct sdhci_pltfm_data *pltfm_data; +const struct dwcmshc_pltfm_data *pltfm_data;int err;u32 extra, caps;
@@ -1146,7 +1231,7 @@ static int dwcmshc_probe(struct platform_device *pdev)return -ENODEV ; } - host =sdhci_pltfm_init (pdev, pltfm_data, + host =sdhci_pltfm_init (pdev, &pltfm_data->pdata,sizeof (struct dwcmshc_priv ));if (IS_ERR (host))return PTR_ERR (host);
@@ -1161,6 +1246,7 @@ static int dwcmshc_probe(struct platform_device *pdev) pltfm_host =sdhci_priv (host); priv =sdhci_pltfm_priv (pltfm_host); + priv->pltfm_data = pltfm_data;if (dev->of_node) { pltfm_host->clk =devm_clk_get (dev,"core" );
@@ -1191,49 +1277,12 @@ static int dwcmshc_probe(struct platform_device *pdev) host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe; host->mmc_host_ops.execute_tuning = dwcmshc_execute_tuning; -if (pltfm_data == &sdhci_dwcmshc_rk35xx_pdata) { - rk_priv =devm_kzalloc (&pdev->dev,sizeof (struct rk35xx_priv ),GFP_KERNEL ); -if (!rk_priv) { - err = -ENOMEM ; - goto err_clk; - } - -if (of_device_is_compatible (pdev->dev.of_node,"rockchip,rk3588-dwcmshc" )) - rk_priv->devtype =DWCMSHC_RK3588 ; -else - rk_priv->devtype =DWCMSHC_RK3568 ; - - priv->priv = rk_priv; - - err =dwcmshc_rk35xx_init (host, priv); +if (pltfm_data->init) { + err = pltfm_data->init (&pdev->dev, host, priv);if (err) goto err_clk; } -if (pltfm_data == &sdhci_dwcmshc_th1520_pdata) { - priv->delay_line =PHY_SDCLKDL_DC_DEFAULT ; - -if (device_property_read_bool (dev,"mmc-ddr-1_8v" ) || -device_property_read_bool (dev,"mmc-hs200-1_8v" ) || -device_property_read_bool (dev,"mmc-hs400-1_8v" )) - priv->flags |=FLAG_IO_FIXED_1V8 ; -else - priv->flags &= ~FLAG_IO_FIXED_1V8 ; - -/* -* start_signal_voltage_switch() will try 3.3V first -* then 1.8V. Use SDHCI_SIGNALING_180 rather than -* SDHCI_SIGNALING_330 to avoid setting voltage to 3.3V -* in sdhci_start_signal_voltage_switch(). -*/ -if (priv->flags &FLAG_IO_FIXED_1V8 ) { - host->flags &= ~SDHCI_SIGNALING_330 ; - host->flags |=SDHCI_SIGNALING_180 ; - } - -sdhci_enable_v4_mode (host); - } -#ifdef CONFIG_ACPI if (pltfm_data == &sdhci_dwcmshc_bf3_pdata)sdhci_enable_v4_mode (host);
@@ -1261,8 +1310,8 @@ static int dwcmshc_probe(struct platform_device *pdev)dwcmshc_cqhci_init (host, pdev); } -if (rk_priv) -dwcmshc_rk35xx_postinit (host, priv); +if (pltfm_data->postinit) + pltfm_data->postinit (host, priv); err =__sdhci_add_host (host);if (err)
@@ -1280,9 +1329,8 @@ static int dwcmshc_probe(struct platform_device *pdev) err_clk:clk_disable_unprepare (pltfm_host->clk);clk_disable_unprepare (priv->bus_clk); -if (rk_priv) -clk_bulk_disable_unprepare (RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); +if (pltfm_data->clks_disable) + pltfm_data->clks_disable (priv); free_pltfm:sdhci_pltfm_free (pdev);return err;
@@ -1304,7 +1352,6 @@ static void dwcmshc_remove(struct platform_device *pdev)struct sdhci_host *host =platform_get_drvdata (pdev);struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct dwcmshc_priv *priv =sdhci_pltfm_priv (pltfm_host); -struct rk35xx_priv *rk_priv = priv->priv;pm_runtime_get_sync (&pdev->dev);pm_runtime_disable (&pdev->dev);
@@ -1316,9 +1363,8 @@ static void dwcmshc_remove(struct platform_device *pdev)clk_disable_unprepare (pltfm_host->clk);clk_disable_unprepare (priv->bus_clk); -if (rk_priv) -clk_bulk_disable_unprepare (RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); +if (priv->pltfm_data->clks_disable) + priv->pltfm_data->clks_disable (priv);sdhci_pltfm_free (pdev); }
@@ -1328,7 +1374,6 @@ static int dwcmshc_suspend(struct device *dev)struct sdhci_host *host =dev_get_drvdata (dev);struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct dwcmshc_priv *priv =sdhci_pltfm_priv (pltfm_host); -struct rk35xx_priv *rk_priv = priv->priv;int ret;pm_runtime_resume (dev);
@@ -1347,9 +1392,8 @@ static int dwcmshc_suspend(struct device *dev)if (!IS_ERR (priv->bus_clk))clk_disable_unprepare (priv->bus_clk); -if (rk_priv) -clk_bulk_disable_unprepare (RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); +if (priv->pltfm_data->clks_disable) + priv->pltfm_data->clks_disable (priv);return ret; }
@@ -1359,7 +1403,6 @@ static int dwcmshc_resume(struct device *dev)struct sdhci_host *host =dev_get_drvdata (dev);struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct dwcmshc_priv *priv =sdhci_pltfm_priv (pltfm_host); -struct rk35xx_priv *rk_priv = priv->priv;int ret; ret =clk_prepare_enable (pltfm_host->clk);
@@ -1372,29 +1415,27 @@ static int dwcmshc_resume(struct device *dev) goto disable_clk; } -if (rk_priv) { - ret =clk_bulk_prepare_enable (RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); +if (priv->pltfm_data->clks_enable) { + ret = priv->pltfm_data->clks_enable (priv);if (ret) goto disable_bus_clk; } ret =sdhci_resume_host (host);if (ret) - goto disable_rockchip_clks; + goto disable_soc_clks;if (host->mmc->caps2 &MMC_CAP2_CQE ) { ret =cqhci_resume (host->mmc);if (ret) - goto disable_rockchip_clks; + goto disable_soc_clks; }return 0 ; -disable_rockchip_clks: -if (rk_priv) -clk_bulk_disable_unprepare (RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); +disable_soc_clks: +if (priv->pltfm_data->clks_disable) + priv->pltfm_data->clks_disable (priv); disable_bus_clk:if (!IS_ERR (priv->bus_clk))clk_disable_unprepare (priv->bus_clk);
Signature · 1 line
2.25.1
Adrian Hunter
maintainerRe: [PATCH v4 1/4] mmc: sdhci-of-dwcmshc: add callback functions for dwcmshc
Quoted 8 lines · Chen Wang
From: Chen Wang <[email protected]>
The current framework is not easily extended to support new SOCs. For example, in the current code we see that the SOC-level structure
rk35xx_privand related logic are distributed in functions such as dwcmshc_probe/dwcmshc_remove/dwcmshc_suspend/......, which is inappropriate.
Quoted 5 lines
The solution is to abstract some possible common operations of soc as dwcmshc platform data. Each soc implements the corresponding callback function according to its own needs.
dwcmshc framework is responsible for calling these callback functions in thosedwcmshc_xxxfunctions at proper positions.
This could be 5 patches:
1. Common bulk optional clocks support (as suggested below)
2. Move functions dwcmshc_rk35xx_init() and dwcmshc_rk35xx_postinit()
3. Factor out code for th1520_init()
4. Factor out code into dwcmshc_rk35xx_init
5. Add dwcmshc_pltfm_data etc
Quoted 11 lines
Signed-off-by Chen Wang <[email protected]>--- drivers/mmc/host/sdhci-of-dwcmshc.c | 327 ++++++++++++++++------------ 1 file changed, 184 insertions(+), 143 deletions(-)drivers/mmc/host/sdhci-of-dwcmshc.c +0
-0
drivers/mmc/host/sdhci-of-dwcmshc.c struct rk35xx_priv { · line 209
Quoted 4 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +1
-0@@ -206,6 +206,7 @@ struct rk35xx_priv {u8 txclk_tapnum; }; +struct dwcmshc_pltfm_data ;
A blank line here would make it be more readable
Quoted 7 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +0
-0struct dwcmshc_priv {struct clk *bus_clk;int vendor_specific_area1;/* P_VENDOR_SPECIFIC_AREA1 reg */ @@ -214,6 +215,16 @@ struct dwcmshc_priv {void *priv;/* pointer to SoC private stuff */ u16 delay_line;u16 flags;
drivers/mmc/host/sdhci-of-dwcmshc.c struct dwcmshc_priv { · line 227
Quoted 10 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +10
-0+ +const struct dwcmshc_pltfm_data *pltfm_data; +}; + +struct dwcmshc_pltfm_data { +const struct sdhci_pltfm_data pdata; +int (*init)(struct device *dev,struct sdhci_host *host,struct dwcmshc_priv *dwc_priv); +void (*postinit)(struct sdhci_host *host,struct dwcmshc_priv *dwc_priv); +int (*clks_enable)(struct dwcmshc_priv *dwc_priv); +void (*clks_disable)(struct dwcmshc_priv *dwc_priv);
In patch 3 you also add bulk clocks, so might as well share that functionality instead of ->clks_enable() etc. e.g. (untested)
drivers/mmc/host/sdhci-of-dwcmshc.c +45 -42
@@ -108,7 +108,6 @@#define DLL_LOCK_WO_TMOUT (x) \ ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \ (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0)) -#define RK35xx_MAX_CLKS 3/* PHY register area pointer */ #define DWC_MSHC_PTR_PHY_R 0x300
@@ -199,23 +198,52 @@ enum dwcmshc_rk_type { };struct rk35xx_priv { -/* Rockchip specified optional clocks */ -struct clk_bulk_data rockchip_clks[RK35xx_MAX_CLKS];struct reset_control *reset;enum dwcmshc_rk_type devtype;u8 txclk_tapnum; }; +#define DWCMSHC_MAX_CLKS 3 +struct dwcmshc_priv {struct clk *bus_clk;int vendor_specific_area1;/* P_VENDOR_SPECIFIC_AREA1 reg */ int vendor_specific_area2;/* P_VENDOR_SPECIFIC_AREA2 reg */ +int num_clks; +struct clk_bulk_data clks[DWCMSHC_MAX_CLKS ]; +void *priv;/* pointer to SoC private stuff */ u16 delay_line;u16 flags; }; +static int dwcmshc_get_enable_clks (struct device *dev,struct dwcmshc_priv *priv, +int num_clks,const char *clk_ids[]) +{ +int err; + +if (num_clks >DWCMSHC_MAX_CLKS ) +return -EINVAL ; + + priv->num_clks = num_clks; + +for (int i =0 ; i < num_clks; i++) + priv->clks[i].id = clk_ids[i]; + + err =devm_clk_bulk_get_optional (dev, priv->num_clks, priv->clks); +if (err) { +dev_err (dev,"failed to get clocks %d\n" , err); +return err; + } + + err =clk_bulk_prepare_enable (priv->num_clks, priv->clks); +if (err) +dev_err (dev,"failed to enable clocks %d\n" , err); + +return err; +} +/* * If DMA addr spans 128MB boundary, we split the DMA transfer into two * so that each DMA transfer doesn't exceed the boundary.
@@ -1036,8 +1064,9 @@ static void dwcmshc_cqhci_init(struct sdhci_host *host, struct platform_device *static int dwcmshc_rk35xx_init (struct sdhci_host *host,struct dwcmshc_priv *dwc_priv) { -int err; +static const char *clk_ids[] = {"axi" ,"block" ,"timer" };struct rk35xx_priv *priv = dwc_priv->priv; +int err; priv->reset =devm_reset_control_array_get_optional_exclusive (mmc_dev (host->mmc));if (IS_ERR (priv->reset)) {
@@ -1046,21 +1075,9 @@ static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwcreturn err; } - priv->rockchip_clks[0 ].id ="axi" ; - priv->rockchip_clks[1 ].id ="block" ; - priv->rockchip_clks[2 ].id ="timer" ; - err =devm_clk_bulk_get_optional (mmc_dev (host->mmc), RK35xx_MAX_CLKS, - priv->rockchip_clks); -if (err) { -dev_err (mmc_dev (host->mmc),"failed to get clocks %d\n" , err); + err =dwcmshc_get_enable_clks (mmc_dev (host->mmc), dwc_priv,ARRAY_SIZE (clk_ids), clk_ids); +if (err)return err; - } - - err =clk_bulk_prepare_enable (RK35xx_MAX_CLKS, priv->rockchip_clks); -if (err) { -dev_err (mmc_dev (host->mmc),"failed to enable clocks %d\n" , err); -return err; - }if (of_property_read_u8 (mmc_dev (host->mmc)->of_node,"rockchip,txclk-tapnum" , &priv->txclk_tapnum))
@@ -1280,9 +1297,7 @@ static int dwcmshc_probe(struct platform_device *pdev) err_clk:clk_disable_unprepare (pltfm_host->clk);clk_disable_unprepare (priv->bus_clk); -if (rk_priv) -clk_bulk_disable_unprepare (RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); +clk_bulk_disable_unprepare (priv->num_clks, priv->clks); free_pltfm:sdhci_pltfm_free (pdev);return err;
@@ -1304,7 +1319,6 @@ static void dwcmshc_remove(struct platform_device *pdev)struct sdhci_host *host =platform_get_drvdata (pdev);struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct dwcmshc_priv *priv =sdhci_pltfm_priv (pltfm_host); -struct rk35xx_priv *rk_priv = priv->priv;pm_runtime_get_sync (&pdev->dev);pm_runtime_disable (&pdev->dev);
@@ -1316,9 +1330,7 @@ static void dwcmshc_remove(struct platform_device *pdev)clk_disable_unprepare (pltfm_host->clk);clk_disable_unprepare (priv->bus_clk); -if (rk_priv) -clk_bulk_disable_unprepare (RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); +clk_bulk_disable_unprepare (priv->num_clks, priv->clks);sdhci_pltfm_free (pdev); }
@@ -1328,7 +1340,6 @@ static int dwcmshc_suspend(struct device *dev)struct sdhci_host *host =dev_get_drvdata (dev);struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct dwcmshc_priv *priv =sdhci_pltfm_priv (pltfm_host); -struct rk35xx_priv *rk_priv = priv->priv;int ret;pm_runtime_resume (dev);
@@ -1347,9 +1358,7 @@ static int dwcmshc_suspend(struct device *dev)if (!IS_ERR (priv->bus_clk))clk_disable_unprepare (priv->bus_clk); -if (rk_priv) -clk_bulk_disable_unprepare (RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); +clk_bulk_disable_unprepare (priv->num_clks, priv->clks);return ret; }
@@ -1359,7 +1368,6 @@ static int dwcmshc_resume(struct device *dev)struct sdhci_host *host =dev_get_drvdata (dev);struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct dwcmshc_priv *priv =sdhci_pltfm_priv (pltfm_host); -struct rk35xx_priv *rk_priv = priv->priv;int ret; ret =clk_prepare_enable (pltfm_host->clk);
@@ -1372,29 +1380,24 @@ static int dwcmshc_resume(struct device *dev) goto disable_clk; } -if (rk_priv) { - ret =clk_bulk_prepare_enable (RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); -if (ret) - goto disable_bus_clk; - } + ret =clk_bulk_prepare_enable (priv->num_clks, priv->clks); +if (ret) + goto disable_bus_clk; ret =sdhci_resume_host (host);if (ret) - goto disable_rockchip_clks; + goto disable_optional_clks;if (host->mmc->caps2 &MMC_CAP2_CQE ) { ret =cqhci_resume (host->mmc);if (ret) - goto disable_rockchip_clks; + goto disable_optional_clks; }return 0 ; -disable_rockchip_clks: -if (rk_priv) -clk_bulk_disable_unprepare (RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); +disable_optional_clks: +clk_bulk_disable_unprepare (priv->num_clks, priv->clks); disable_bus_clk:if (!IS_ERR (priv->bus_clk))clk_disable_unprepare (priv->bus_clk);
Quoted 459 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +173
-143};/* @@ -681,6 +692,92 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask)sdhci_reset (host, mask); } +static int dwcmshc_rk35xx_init (struct device *dev,struct sdhci_host *host, +struct dwcmshc_priv *dwc_priv) +{ +int err; +struct rk35xx_priv *priv; + + priv =devm_kzalloc (dev,sizeof (struct rk35xx_priv ),GFP_KERNEL ); +if (!priv) +return -ENOMEM ; + +if (of_device_is_compatible (dev->of_node,"rockchip,rk3588-dwcmshc" )) + priv->devtype =DWCMSHC_RK3588 ; +else + priv->devtype =DWCMSHC_RK3568 ; + + priv->reset =devm_reset_control_array_get_optional_exclusive (mmc_dev (host->mmc)); +if (IS_ERR (priv->reset)) { + err =PTR_ERR (priv->reset); +dev_err (mmc_dev (host->mmc),"failed to get reset control %d\n" , err); +return err; + } + + priv->rockchip_clks[0 ].id ="axi" ; + priv->rockchip_clks[1 ].id ="block" ; + priv->rockchip_clks[2 ].id ="timer" ; + err =devm_clk_bulk_get_optional (mmc_dev (host->mmc), RK35xx_MAX_CLKS, + priv->rockchip_clks); +if (err) { +dev_err (mmc_dev (host->mmc),"failed to get clocks %d\n" , err); +return err; + } + + err =clk_bulk_prepare_enable (RK35xx_MAX_CLKS, priv->rockchip_clks); +if (err) { +dev_err (mmc_dev (host->mmc),"failed to enable clocks %d\n" , err); +return err; + } + +if (of_property_read_u8 (mmc_dev (host->mmc)->of_node,"rockchip,txclk-tapnum" , + &priv->txclk_tapnum)) + priv->txclk_tapnum =DLL_TXCLK_TAPNUM_DEFAULT ; + +/* Disable cmd conflict check */ +sdhci_writel (host,0x0 , dwc_priv->vendor_specific_area1 +DWCMSHC_HOST_CTRL3 ); +/* Reset previous settings */ +sdhci_writel (host,0 ,DWCMSHC_EMMC_DLL_TXCLK ); +sdhci_writel (host,0 ,DWCMSHC_EMMC_DLL_STRBIN ); + + dwc_priv->priv = priv; + +return 0 ; +} + +static void dwcmshc_rk35xx_postinit (struct sdhci_host *host,struct dwcmshc_priv *dwc_priv) +{ +/* +* Don't support highspeed bus mode with low clk speed as we +* cannot use DLL for this condition. +*/ +if (host->mmc->f_max <=52000000 ) { +dev_info (mmc_dev (host->mmc),"Disabling HS200/HS400, frequency too low (%d)\n" , + host->mmc->f_max); + host->mmc->caps2 &= ~(MMC_CAP2_HS200 |MMC_CAP2_HS400 ); + host->mmc->caps &= ~(MMC_CAP_3_3V_DDR |MMC_CAP_1_8V_DDR ); + } +} + +static int rk35xx_clks_enable (struct dwcmshc_priv *dwc_priv) +{ +struct rk35xx_priv *priv = dwc_priv->priv; +int ret =0 ; + +if (priv) + ret =clk_bulk_prepare_enable (RK35xx_MAX_CLKS, priv->rockchip_clks); +return ret; +} + +static void rk35xx_clks_disable (struct dwcmshc_priv *dwc_priv) +{ +struct rk35xx_priv *priv = dwc_priv->priv; + +if (priv) +clk_bulk_disable_unprepare (RK35xx_MAX_CLKS, + priv->rockchip_clks); +} +static int th1520_execute_tuning (struct sdhci_host *host,u32 opcode) {struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);@@ -755,6 +852,35 @@ static void th1520_sdhci_reset(struct sdhci_host *host, u8 mask) } } +static int th1520_init (struct device *dev, +struct sdhci_host *host, +struct dwcmshc_priv *dwc_priv) +{ + dwc_priv->delay_line =PHY_SDCLKDL_DC_DEFAULT ; + +if (device_property_read_bool (dev,"mmc-ddr-1_8v" ) || +device_property_read_bool (dev,"mmc-hs200-1_8v" ) || +device_property_read_bool (dev,"mmc-hs400-1_8v" )) + dwc_priv->flags |=FLAG_IO_FIXED_1V8 ; +else + dwc_priv->flags &= ~FLAG_IO_FIXED_1V8 ; + +/* +* start_signal_voltage_switch() will try 3.3V first +* then 1.8V. Use SDHCI_SIGNALING_180 rather than +* SDHCI_SIGNALING_330 to avoid setting voltage to 3.3V +* in sdhci_start_signal_voltage_switch(). +*/ +if (dwc_priv->flags &FLAG_IO_FIXED_1V8 ) { + host->flags &= ~SDHCI_SIGNALING_330 ; + host->flags |=SDHCI_SIGNALING_180 ; + } + +sdhci_enable_v4_mode (host); + +return 0 ; +} +static void cv18xx_sdhci_reset (struct sdhci_host *host,u8 mask) {struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);@@ -932,39 +1058,54 @@ static const struct sdhci_ops sdhci_dwcmshc_cv18xx_ops = { .platform_execute_tuning = cv18xx_sdhci_execute_tuning, }; -static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { - .ops = &sdhci_dwcmshc_ops, - .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , - .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN , +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_pdata = { + .pdata = { + .ops = &sdhci_dwcmshc_ops, + .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , + .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN , + }, };#ifdef CONFIG_ACPI -static const struct sdhci_pltfm_data sdhci_dwcmshc_bf3_pdata = { - .ops = &sdhci_dwcmshc_ops, - .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , - .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN | -SDHCI_QUIRK2_ACMD23_BROKEN , +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_bf3_pdata = { + .pdata = { + .ops = &sdhci_dwcmshc_ops, + .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , + .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN | +SDHCI_QUIRK2_ACMD23_BROKEN , + }, };#endif -static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = { - .ops = &sdhci_dwcmshc_rk35xx_ops, - .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | -SDHCI_QUIRK_BROKEN_TIMEOUT_VAL , - .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN | -SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN , +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_rk35xx_pdata = { + .pdata = { + .ops = &sdhci_dwcmshc_rk35xx_ops, + .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | +SDHCI_QUIRK_BROKEN_TIMEOUT_VAL , + .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN | +SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN , + }, + .init = dwcmshc_rk35xx_init, + .postinit = dwcmshc_rk35xx_postinit, + .clks_enable = rk35xx_clks_enable, + .clks_disable = rk35xx_clks_disable, }; -static const struct sdhci_pltfm_data sdhci_dwcmshc_th1520_pdata = { - .ops = &sdhci_dwcmshc_th1520_ops, - .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , - .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN , +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_th1520_pdata = { + .pdata = { + .ops = &sdhci_dwcmshc_th1520_ops, + .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , + .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN , + }, + .init = th1520_init, }; -static const struct sdhci_pltfm_data sdhci_dwcmshc_cv18xx_pdata = { - .ops = &sdhci_dwcmshc_cv18xx_ops, - .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , - .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN , +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_cv18xx_pdata = { + .pdata = { + .ops = &sdhci_dwcmshc_cv18xx_ops, + .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , + .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN , + }, };static const struct cqhci_host_ops dwcmshc_cqhci_ops = {@@ -1034,61 +1175,6 @@ static void dwcmshc_cqhci_init(struct sdhci_host *host, struct platform_device * host->mmc->caps2 &= ~(MMC_CAP2_CQE |MMC_CAP2_CQE_DCMD ); } -static int dwcmshc_rk35xx_init (struct sdhci_host *host,struct dwcmshc_priv *dwc_priv) -{ -int err; -struct rk35xx_priv *priv = dwc_priv->priv; - - priv->reset =devm_reset_control_array_get_optional_exclusive (mmc_dev (host->mmc)); -if (IS_ERR (priv->reset)) { - err =PTR_ERR (priv->reset); -dev_err (mmc_dev (host->mmc),"failed to get reset control %d\n" , err); -return err; - } - - priv->rockchip_clks[0 ].id ="axi" ; - priv->rockchip_clks[1 ].id ="block" ; - priv->rockchip_clks[2 ].id ="timer" ; - err =devm_clk_bulk_get_optional (mmc_dev (host->mmc), RK35xx_MAX_CLKS, - priv->rockchip_clks); -if (err) { -dev_err (mmc_dev (host->mmc),"failed to get clocks %d\n" , err); -return err; - } - - err =clk_bulk_prepare_enable (RK35xx_MAX_CLKS, priv->rockchip_clks); -if (err) { -dev_err (mmc_dev (host->mmc),"failed to enable clocks %d\n" , err); -return err; - } - -if (of_property_read_u8 (mmc_dev (host->mmc)->of_node,"rockchip,txclk-tapnum" , - &priv->txclk_tapnum)) - priv->txclk_tapnum =DLL_TXCLK_TAPNUM_DEFAULT ; - -/* Disable cmd conflict check */ -sdhci_writel (host,0x0 , dwc_priv->vendor_specific_area1 +DWCMSHC_HOST_CTRL3 ); -/* Reset previous settings */ -sdhci_writel (host,0 ,DWCMSHC_EMMC_DLL_TXCLK ); -sdhci_writel (host,0 ,DWCMSHC_EMMC_DLL_STRBIN ); - -return 0 ; -} - -static void dwcmshc_rk35xx_postinit (struct sdhci_host *host,struct dwcmshc_priv *dwc_priv) -{ -/* -* Don't support highspeed bus mode with low clk speed as we -* cannot use DLL for this condition. -*/ -if (host->mmc->f_max <=52000000 ) { -dev_info (mmc_dev (host->mmc),"Disabling HS200/HS400, frequency too low (%d)\n" , - host->mmc->f_max); - host->mmc->caps2 &= ~(MMC_CAP2_HS200 |MMC_CAP2_HS400 ); - host->mmc->caps &= ~(MMC_CAP_3_3V_DDR |MMC_CAP_1_8V_DDR ); - } -} -static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { { .compatible ="rockchip,rk3588-dwcmshc" ,@@ -1135,8 +1221,7 @@ static int dwcmshc_probe(struct platform_device *pdev)struct sdhci_pltfm_host *pltfm_host;struct sdhci_host *host;struct dwcmshc_priv *priv; -struct rk35xx_priv *rk_priv =NULL ; -const struct sdhci_pltfm_data *pltfm_data; +const struct dwcmshc_pltfm_data *pltfm_data;int err;u32 extra, caps;@@ -1146,7 +1231,7 @@ static int dwcmshc_probe(struct platform_device *pdev)return -ENODEV ; } - host =sdhci_pltfm_init (pdev, pltfm_data, + host =sdhci_pltfm_init (pdev, &pltfm_data->pdata,sizeof (struct dwcmshc_priv ));if (IS_ERR (host))return PTR_ERR (host);@@ -1161,6 +1246,7 @@ static int dwcmshc_probe(struct platform_device *pdev) pltfm_host =sdhci_priv (host); priv =sdhci_pltfm_priv (pltfm_host); + priv->pltfm_data = pltfm_data;if (dev->of_node) { pltfm_host->clk =devm_clk_get (dev,"core" );@@ -1191,49 +1277,12 @@ static int dwcmshc_probe(struct platform_device *pdev) host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe; host->mmc_host_ops.execute_tuning = dwcmshc_execute_tuning; -if (pltfm_data == &sdhci_dwcmshc_rk35xx_pdata) { - rk_priv =devm_kzalloc (&pdev->dev,sizeof (struct rk35xx_priv ),GFP_KERNEL ); -if (!rk_priv) { - err = -ENOMEM ; - goto err_clk; - } - -if (of_device_is_compatible (pdev->dev.of_node,"rockchip,rk3588-dwcmshc" )) - rk_priv->devtype =DWCMSHC_RK3588 ; -else - rk_priv->devtype =DWCMSHC_RK3568 ; - - priv->priv = rk_priv; - - err =dwcmshc_rk35xx_init (host, priv); +if (pltfm_data->init) { + err = pltfm_data->init (&pdev->dev, host, priv);if (err) goto err_clk; } -if (pltfm_data == &sdhci_dwcmshc_th1520_pdata) { - priv->delay_line =PHY_SDCLKDL_DC_DEFAULT ; - -if (device_property_read_bool (dev,"mmc-ddr-1_8v" ) || -device_property_read_bool (dev,"mmc-hs200-1_8v" ) || -device_property_read_bool (dev,"mmc-hs400-1_8v" )) - priv->flags |=FLAG_IO_FIXED_1V8 ; -else - priv->flags &= ~FLAG_IO_FIXED_1V8 ; - -/* -* start_signal_voltage_switch() will try 3.3V first -* then 1.8V. Use SDHCI_SIGNALING_180 rather than -* SDHCI_SIGNALING_330 to avoid setting voltage to 3.3V -* in sdhci_start_signal_voltage_switch(). -*/ -if (priv->flags &FLAG_IO_FIXED_1V8 ) { - host->flags &= ~SDHCI_SIGNALING_330 ; - host->flags |=SDHCI_SIGNALING_180 ; - } - -sdhci_enable_v4_mode (host); - } -#ifdef CONFIG_ACPI if (pltfm_data == &sdhci_dwcmshc_bf3_pdata)sdhci_enable_v4_mode (host);@@ -1261,8 +1310,8 @@ static int dwcmshc_probe(struct platform_device *pdev)dwcmshc_cqhci_init (host, pdev); } -if (rk_priv) -dwcmshc_rk35xx_postinit (host, priv); +if (pltfm_data->postinit) + pltfm_data->postinit (host, priv); err =__sdhci_add_host (host);if (err)@@ -1280,9 +1329,8 @@ static int dwcmshc_probe(struct platform_device *pdev) err_clk:clk_disable_unprepare (pltfm_host->clk);clk_disable_unprepare (priv->bus_clk); -if (rk_priv) -clk_bulk_disable_unprepare (RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); +if (pltfm_data->clks_disable) + pltfm_data->clks_disable (priv); free_pltfm:sdhci_pltfm_free (pdev);return err;@@ -1304,7 +1352,6 @@ static void dwcmshc_remove(struct platform_device *pdev)struct sdhci_host *host =platform_get_drvdata (pdev);struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct dwcmshc_priv *priv =sdhci_pltfm_priv (pltfm_host); -struct rk35xx_priv *rk_priv = priv->priv;pm_runtime_get_sync (&pdev->dev);pm_runtime_disable (&pdev->dev);@@ -1316,9 +1363,8 @@ static void dwcmshc_remove(struct platform_device *pdev)clk_disable_unprepare (pltfm_host->clk);clk_disable_unprepare (priv->bus_clk); -if (rk_priv) -clk_bulk_disable_unprepare (RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); +if (priv->pltfm_data->clks_disable) + priv->pltfm_data->clks_disable (priv);sdhci_pltfm_free (pdev); }@@ -1328,7 +1374,6 @@ static int dwcmshc_suspend(struct device *dev)struct sdhci_host *host =dev_get_drvdata (dev);struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct dwcmshc_priv *priv =sdhci_pltfm_priv (pltfm_host); -struct rk35xx_priv *rk_priv = priv->priv;int ret;pm_runtime_resume (dev);@@ -1347,9 +1392,8 @@ static int dwcmshc_suspend(struct device *dev)if (!IS_ERR (priv->bus_clk))clk_disable_unprepare (priv->bus_clk); -if (rk_priv) -clk_bulk_disable_unprepare (RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); +if (priv->pltfm_data->clks_disable) + priv->pltfm_data->clks_disable (priv);return ret; }@@ -1359,7 +1403,6 @@ static int dwcmshc_resume(struct device *dev)struct sdhci_host *host =dev_get_drvdata (dev);struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct dwcmshc_priv *priv =sdhci_pltfm_priv (pltfm_host); -struct rk35xx_priv *rk_priv = priv->priv;int ret; ret =clk_prepare_enable (pltfm_host->clk);@@ -1372,29 +1415,27 @@ static int dwcmshc_resume(struct device *dev) goto disable_clk; } -if (rk_priv) { - ret =clk_bulk_prepare_enable (RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); +if (priv->pltfm_data->clks_enable) { + ret = priv->pltfm_data->clks_enable (priv);if (ret) goto disable_bus_clk; } ret =sdhci_resume_host (host);if (ret) - goto disable_rockchip_clks; + goto disable_soc_clks;if (host->mmc->caps2 &MMC_CAP2_CQE ) { ret =cqhci_resume (host->mmc);if (ret) - goto disable_rockchip_clks; + goto disable_soc_clks; }return 0 ; -disable_rockchip_clks: -if (rk_priv) -clk_bulk_disable_unprepare (RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); +disable_soc_clks: +if (priv->pltfm_data->clks_disable) + priv->pltfm_data->clks_disable (priv); disable_bus_clk:if (!IS_ERR (priv->bus_clk))clk_disable_unprepare (priv->bus_clk);
Re: [PATCH v4 1/4] mmc: sdhci-of-dwcmshc: add callback functions for dwcmshc
Quoted 14 lines · Adrian Hunter
Quoted 8 lines · Chen Wang
From: Chen Wang <[email protected]>
The current framework is not easily extended to support new SOCs. For example, in the current code we see that the SOC-level structure
rk35xx_privand related logic are distributed in functions such as dwcmshc_probe/dwcmshc_remove/dwcmshc_suspend/......, which is inappropriate.Quoted 5 lines
The solution is to abstract some possible common operations of soc as dwcmshc platform data. Each soc implements the corresponding callback function according to its own needs.
dwcmshc framework is responsible for calling these callback functions in thosedwcmshc_xxxfunctions at proper positions.
Quoted 6 lines
This could be 5 patches:
1. Common bulk optional clocks support (as suggested below)
2. Move functionsdwcmshc_rk35xx_init()anddwcmshc_rk35xx_postinit()
3. Factor out code forth1520_init()
4. Factor out code intodwcmshc_rk35xx_init
5. Adddwcmshc_pltfm_dataetc
Hi, I'm back, and I finally found the time to continue this work.
Thank you Adrian for your execllent input, I will investigate and rework the code as per your suggestion.
Regards,
Chen
[......]
PATCH v4 2/4 dt-bindings: mmc: sdhci-of-dwcmhsc: Add Sophgo SG2042 support
In reply to Chen WangFrom: Chen Wang <[email protected]>
SG2042 use Synopsys dwcnshc IP for SD/eMMC controllers.
SG2042 defines 3 clocks for SD/eMMC controllers.
- AXI_EMMC/AXI_SD for aclk/hclk(Bus interface clocks in DWC_mshc) and blck(Core Base Clock in DWC_mshc), these 3 clocks share one source, so reuse existing "core".
- 100K_EMMC/100K_SD for cqetmclk(Timer clocks in DWC_mshc), so reuse existing "timer" which was added for rockchip specified.
- EMMC_100M/SD_100M for cclk(Card clocks in DWC_mshc), add new "card".
Adding example for sg2042.
--- .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 69 +++++++++++++------ 1 file changed, 49 insertions(+), 20 deletions(-)
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +49 -20
@@ -21,6 +21,7 @@ properties: - snps,dwcmshc-sdhci - sophgo,cv1800b-dwcmshc - sophgo,sg2002-dwcmshc + - sophgo,sg2042-dwcmshc - thead,th1520-dwcmshc reg:
@@ -29,25 +30,6 @@ properties: interrupts: maxItems: 1 - clocks: - minItems: 1 - items: - - description: core clock - - description: bus clock for optional - - description: axi clock for rockchip specified - - description: block clock for rockchip specified - - description: timer clock for rockchip specified - - - clock-names: - minItems: 1 - items: - - const: core - - const: bus - - const: axi - - const: block - - const: timer - resets: maxItems: 5
@@ -63,6 +45,43 @@ properties: description: Specify the number of delay for tx sampling. $ref: /schemas/types.yaml#/definitions/uint8 +if: + properties: + compatible: + contains: + const: sophgo,sg2042-dwcmshc +then: + properties: + clocks: + items: + - description: core clock + - description: timer clock + - description: card clock + + clock-names: + items: + - const: core + - const: timer + - const: card +else: + properties: + clocks: + minItems: 1 + items: + - description: core clock + - description: bus clock for optional + - description: axi clock for rockchip specified + - description: block clock for rockchip specified + - description: timer clock for rockchip specified + + clock-names: + minItems: 1 + items: + - const: core + - const: bus + - const: axi + - const: block + - const: timer required: - compatible
@@ -96,5 +115,15 @@ examples: #address-cells = <1>; #size-cells = <0>; }; - + - | + mmc@bb0000 { + compatible = "sophgo,sg2042-dwcmshc"; + reg = <0xcc000 0x1000>; + interrupts = <0 25 0x4>; + clocks = <&cru 17>, <&cru 18>, <&cru 19>; + clock-names = "core", "timer", "card"; + bus-width = <8>; + #address-cells = <1>; + #size-cells = <0>; + }; ...
Signature · 1 line
2.25.1
Re: [PATCH v4 2/4] dt-bindings: mmc: sdhci-of-dwcmhsc: Add Sophgo SG2042 support
Quoted 32 lines · Chen Wang
From: Chen Wang <[email protected]>
SG2042 use Synopsys dwcnshc IP for SD/eMMC controllers.
SG2042 defines 3 clocks for SD/eMMC controllers.
- AXI_EMMC/AXI_SD for aclk/hclk(Bus interface clocks inDWC_mshc) andblck(Core Base Clock in DWC_mshc), these 3 clocks share one source, so reuse existing "core".
- 100K_EMMC/100K_SD forcqetmclk(Timer clocks in DWC_mshc), so reuse existing "timer" which was added for rockchip specified.
- EMMC_100M/SD_100M forcclk(Card clocks in DWC_mshc), add new "card".Adding example for sg2042.
Signed-off-by Chen Wang <[email protected]>--- .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 69 +++++++++++++------ 1 file changed, 49 insertions(+), 20 deletions(-)Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +1
-0@@ -21,6 +21,7 @@ properties: - snps,dwcmshc-sdhci - sophgo,cv1800b-dwcmshc - sophgo,sg2002-dwcmshc + - sophgo,sg2042-dwcmshc - thead,th1520-dwcmshc reg:
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml properties: · line 32
Quoted 4 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +0
-1@@ -29,25 +30,6 @@ properties: interrupts: maxItems: 1 - clocks:
Widest constraints stay here.
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml properties: · line 43
Quoted 11 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +0
-11- minItems: 1 - items: - - description: core clock - - description: bus clock for optional - - description: axi clock for rockchip specified - - description: block clock for rockchip specified - - description: timer clock for rockchip specified - - - clock-names: - minItems: 1
Widest constraints stay here.
Quoted 11 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +0
-7- items: - - const: core - - const: bus - - const: axi - - const: block - - const: timer - resets: maxItems: 5
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml properties: · line 48
Quoted 4 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +1
-0@@ -63,6 +45,43 @@ properties: description: Specify the number of delay for tx sampling. $ref: /schemas/types.yaml#/definitions/uint8 +if:
This should be under allOf block and move the allOf to expected place like in example schema. So after required: block.
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml properties: · line 59
Quoted 11 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +11
-0+ properties: + compatible: + contains: + const: sophgo,sg2042-dwcmshc +then: + properties: + clocks: + items: + - description: core clock + - description: timer clock + - description: card clock
What is the card clock? It's suspicious to see new clock not matching anything from previous ones.
Quoted 29 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +25
-0+ + clock-names: + items: + - const: core + - const: timer + - const: card +else: + properties: + clocks: + minItems: 1 + items: + - description: core clock + - description: bus clock for optional + - description: axi clock for rockchip specified + - description: block clock for rockchip specified + - description: timer clock for rockchip specified + + clock-names: + minItems: 1 + items: + - const: core + - const: bus + - const: axi + - const: block + - const: timer required: - compatible
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml examples: · line 122
Quoted 9 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +5
-1@@ -96,5 +115,15 @@ examples: #address-cells = <1>; #size-cells = <0>; }; - + - | + mmc@bb0000 { + compatible = "sophgo,sg2042-dwcmshc"; + reg = <0xcc000 0x1000>; + interrupts = <0 25 0x4>;
Use defines... or actually drop entire example, no point to keep growing them.
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml examples: · line 128
Quoted 7 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +6
-0+ clocks = <&cru 17>, <&cru 18>, <&cru 19>; + clock-names = "core", "timer", "card"; + bus-width = <8>; + #address-cells = <1>; + #size-cells = <0>; + };
Best regards,
Krzysztof
Re: [PATCH v4 2/4] dt-bindings: mmc: sdhci-of-dwcmhsc: Add Sophgo SG2042 support
Quoted 39 lines · Krzysztof Kozlowski
Quoted 32 lines · Chen Wang
From: Chen Wang <[email protected]>
SG2042 use Synopsys dwcnshc IP for SD/eMMC controllers.
SG2042 defines 3 clocks for SD/eMMC controllers.
- AXI_EMMC/AXI_SD for aclk/hclk(Bus interface clocks inDWC_mshc) andblck(Core Base Clock in DWC_mshc), these 3 clocks share one source, so reuse existing "core".
- 100K_EMMC/100K_SD forcqetmclk(Timer clocks in DWC_mshc), so reuse existing "timer" which was added for rockchip specified.
- EMMC_100M/SD_100M forcclk(Card clocks in DWC_mshc), add new "card".Adding example for sg2042.
Signed-off-by Chen Wang <[email protected]>--- .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 69 +++++++++++++------ 1 file changed, 49 insertions(+), 20 deletions(-)Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +1
-0@@ -21,6 +21,7 @@ properties: - snps,dwcmshc-sdhci - sophgo,cv1800b-dwcmshc - sophgo,sg2002-dwcmshc + - sophgo,sg2042-dwcmshc - thead,th1520-dwcmshc reg:Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml properties: · line 32
Quoted 4 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +0
-1@@ -29,25 +30,6 @@ properties: interrupts: maxItems: 1 - clocks:Widest constraints stay here.
Quoted 12 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml properties: · line 43
Quoted 11 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +0
-11- minItems: 1 - items: - - description: core clock - - description: bus clock for optional - - description: axi clock for rockchip specified - - description: block clock for rockchip specified - - description: timer clock for rockchip specified - - - clock-names: - minItems: 1Widest constraints stay here.
hi, Krzysztof,
Please ask you a question about this widest constraints, I write bindings as below:
```yaml properties: ...... clocks: minItems: 1 clock-names: minItems: 1 ...... allOf: - $ref: mmc-controller.yaml# - if: properties: compatible: contains: const: sophgo,sg2042-dwcmshc then: properties: clocks: minItems: 1 items: - description: core clock - description: bus clock - description: timer clock-names: minItems: 1 items: - const: core - const: bus - const: timer else: properties: clocks: minItems: 1 items: - description: core clock - description: bus clock for optional - description: axi clock for rockchip specified - description: block clock for rockchip specified - description: timer clock for rockchip specified clock-names: minItems: 1 items: - const: core - const: bus - const: axi - const: block - const: timer ```
and with DTS as below:
```dts
sd: mmc@704002b000 {
compatible = "sophgo,sg2042-dwcmshc";
reg = <0x70 0x4002b000 0x0 0x1000>;
interrupt-parent = <&intc>;
interrupts = <136 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clkgen GATE_CLK_SD_100M>,
<&clkgen GATE_CLK_AXI_SD>,
<&clkgen GATE_CLK_100K_SD>;
clock-names = "core",
"bus",
"timer";
status = "disabled";
};
```dtb check will report error:
``` .../arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dtb: mmc@704002b000: clocks: [[84, 38], [84, 64], [84, 76]] is too long from schema $id: http://devicetree.org/schemas/mmc/snps,dwcmshc-sdhci.yaml# .../arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dtb: mmc@704002b000: clock-names: ['core', 'bus', 'timer'] is too long from schema $id: http://devicetree.org/schemas/mmc/snps,dwcmshc-sdhci.yaml# ```
After I removed the widest constraints from the binding file, dtb check passes.
Not sure if my understanding is wrong. Do you know what's the problem here? Seems the widest constraints is not needed,
Thanks,
Chen
[......]
Re: [PATCH v4 2/4] dt-bindings: mmc: sdhci-of-dwcmhsc: Add Sophgo SG2042 support
Quoted 63 lines · Chen Wang
Quoted 39 lines · Krzysztof Kozlowski
Quoted 32 lines · Chen Wang
From: Chen Wang <[email protected]>
SG2042 use Synopsys dwcnshc IP for SD/eMMC controllers.
SG2042 defines 3 clocks for SD/eMMC controllers.
- AXI_EMMC/AXI_SD for aclk/hclk(Bus interface clocks inDWC_mshc) andblck(Core Base Clock in DWC_mshc), these 3 clocks share one source, so reuse existing "core".
- 100K_EMMC/100K_SD forcqetmclk(Timer clocks in DWC_mshc), so reuse existing "timer" which was added for rockchip specified.
- EMMC_100M/SD_100M forcclk(Card clocks in DWC_mshc), add new "card".Adding example for sg2042.
Signed-off-by Chen Wang <[email protected]>--- .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 69 +++++++++++++------ 1 file changed, 49 insertions(+), 20 deletions(-)Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +1
-0@@ -21,6 +21,7 @@ properties: - snps,dwcmshc-sdhci - sophgo,cv1800b-dwcmshc - sophgo,sg2002-dwcmshc + - sophgo,sg2042-dwcmshc - thead,th1520-dwcmshc reg:Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml properties: · line 32
Quoted 4 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +0
-1@@ -29,25 +30,6 @@ properties: interrupts: maxItems: 1 - clocks:Widest constraints stay here.
Quoted 12 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml properties: · line 43
Quoted 11 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +0
-11- minItems: 1 - items: - - description: core clock - - description: bus clock for optional - - description: axi clock for rockchip specified - - description: block clock for rockchip specified - - description: timer clock for rockchip specified - - - clock-names: - minItems: 1Widest constraints stay here.
hi, Krzysztof,
Please ask you a question about this widest constraints, I write bindings as below:
```yaml
properties:
Quoted 7 lines
......
clocks:
minItems: 1clock-names:
minItems: 1
So 1000 clocks is correct? You can always look at helpful examples from my slides... or another example:
Best regards,
Krzysztof
Re: [PATCH v4 2/4] dt-bindings: mmc: sdhci-of-dwcmhsc: Add Sophgo SG2042 support
In reply to Chen WangQuoted 8 lines · Chen Wang
From: Chen Wang <[email protected]>
SG2042 use Synopsys dwcnshc IP for SD/eMMC controllers.
SG2042 defines 3 clocks for SD/eMMC controllers.
- AXI_EMMC/AXI_SD for aclk/hclk(Bus interface clocks inDWC_mshc) andblck(Core Base Clock in DWC_mshc), these 3 clocks share one source, so reuse existing "core".
No, this seems not correct. This should be the "bus" clk, and your above sentence "aclk/hclk(Bus interface clocks in DWC_mshc)" implies this clk is for bus
Quoted 3 lines
- 100K_EMMC/100K_SD for
cqetmclk(Timer clocks in DWC_mshc), so reuse existing "timer" which was added for rockchip specified.
- EMMC_100M/SD_100M forcclk(Card clocks in DWC_mshc), add new "card".
I think this is "core" clk, no? Plz check which internal clks' clock source is the so called EMMC_100M/SD_100M.
Quoted 110 lines
Adding example for sg2042.
Signed-off-by Chen Wang <[email protected]>--- .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 69 +++++++++++++------ 1 file changed, 49 insertions(+), 20 deletions(-)Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +49
-20@@ -21,6 +21,7 @@ properties: - snps,dwcmshc-sdhci - sophgo,cv1800b-dwcmshc - sophgo,sg2002-dwcmshc + - sophgo,sg2042-dwcmshc - thead,th1520-dwcmshc reg:@@ -29,25 +30,6 @@ properties: interrupts: maxItems: 1 - clocks: - minItems: 1 - items: - - description: core clock - - description: bus clock for optional - - description: axi clock for rockchip specified - - description: block clock for rockchip specified - - description: timer clock for rockchip specified - - - clock-names: - minItems: 1 - items: - - const: core - - const: bus - - const: axi - - const: block - - const: timer - resets: maxItems: 5@@ -63,6 +45,43 @@ properties: description: Specify the number of delay for tx sampling. $ref: /schemas/types.yaml#/definitions/uint8 +if: + properties: + compatible: + contains: + const: sophgo,sg2042-dwcmshc +then: + properties: + clocks: + items: + - description: core clock + - description: timer clock + - description: card clock + + clock-names: + items: + - const: core + - const: timer + - const: card +else: + properties: + clocks: + minItems: 1 + items: + - description: core clock + - description: bus clock for optional + - description: axi clock for rockchip specified + - description: block clock for rockchip specified + - description: timer clock for rockchip specified + + clock-names: + minItems: 1 + items: + - const: core + - const: bus + - const: axi + - const: block + - const: timer required: - compatible@@ -96,5 +115,15 @@ examples: #address-cells = <1>; #size-cells = <0>; }; - + - | + mmc@bb0000 { + compatible = "sophgo,sg2042-dwcmshc"; + reg = <0xcc000 0x1000>; + interrupts = <0 25 0x4>; + clocks = <&cru 17>, <&cru 18>, <&cru 19>; + clock-names = "core", "timer", "card"; + bus-width = <8>; + #address-cells = <1>; + #size-cells = <0>; + };Signature · 1 line
2.25.1
Re: [PATCH v4 2/4] dt-bindings: mmc: sdhci-of-dwcmhsc: Add Sophgo SG2042 support
Quoted 13 lines · Jisheng Zhang
Quoted 8 lines · Chen Wang
From: Chen Wang <[email protected]>
SG2042 use Synopsys dwcnshc IP for SD/eMMC controllers.
SG2042 defines 3 clocks for SD/eMMC controllers.
- AXI_EMMC/AXI_SD for aclk/hclk(Bus interface clocks inDWC_mshc) andblck(Core Base Clock in DWC_mshc), these 3 clocks share one source, so reuse existing "core".No, this seems not correct. This should be the "bus" clk, and your above sentence "aclk/hclk(Bus interface clocks in
DWC_mshc)" implies this clk is for bus
Quoted 5 lines
Quoted 3 lines
- 100K_EMMC/100K_SD for
cqetmclk(Timer clocks in DWC_mshc), so reuse existing "timer" which was added for rockchip specified.
- EMMC_100M/SD_100M forcclk(Card clocks in DWC_mshc), add new "card".I think this is "core" clk, no? Plz check which internal clks' clock source is the so called EMMC_100M/SD_100M.
hi, Jisheng,
Just want to double-confirm, corresponding to the definition of clock in the dwc-mshc specification, what's the "core" clock in the snps,dwcmshc-sdhci.yaml?
I get following clock definitions in user-guide of dwc-mshc specification, in section 1.8 "Speed and Clock Requirements"
- 1.8.1 Bus Interface Clocks,which are aclk and m_hclk/hclk
- 1.8.2 Timer Clocks,which are tmclk,cqetmclk
- 1.8.3 Card Clocks, whichi is cclk
- 1.8.4 Core Base Clock,which is bclk
I used to think "core" is "Core Base Clock".
[......]
PATCH v4 3/4 mmc: sdhci-of-dwcmshc: Add support for Sophgo SG2042
In reply to Chen WangFrom: Chen Wang <[email protected]>
Add support for the mmc controller of Sophgo SG2042.
SG2042 uses Synopsys PHY the same as TH1520 so we reuse the tuning logic from TH1520. Besides this, this patch implement some SG2042 specific work, such as clocks and reset ops.
--- drivers/mmc/host/sdhci-of-dwcmshc.c | 172 ++++++++++++++++++++++++++-- 1 file changed, 165 insertions(+), 7 deletions(-)
drivers/mmc/host/sdhci-of-dwcmshc.c +165 -7
@@ -114,12 +114,15 @@#define DWC_MSHC_PTR_PHY_R 0x300/* PHY general configuration */ -#define PHY_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x00) -#define PHY_CNFG_RSTN_DEASSERT 0x1/* Deassert PHY reset */ -#define PHY_CNFG_PAD_SP_MASK GENMASK(19, 16)/* bits [19:16] */ -#define PHY_CNFG_PAD_SP 0x0c/* PMOS TX drive strength */ -#define PHY_CNFG_PAD_SN_MASK GENMASK(23, 20)/* bits [23:20] */ -#define PHY_CNFG_PAD_SN 0x0c/* NMOS TX drive strength */ +#define PHY_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x00) +#define PHY_CNFG_RSTN_DEASSERT 0x1/* Deassert PHY reset */ +#define PHY_CNFG_PHY_PWRGOOD_MASK BIT_MASK(1)/* bit [1] */ +#define PHY_CNFG_PAD_SP_MASK GENMASK(19, 16)/* bits [19:16] */ +#define PHY_CNFG_PAD_SP 0x0c/* PMOS TX drive strength */ +#define PHY_CNFG_PAD_SP_SG2042 0x09/* PMOS TX drive strength for SG2042 */ +#define PHY_CNFG_PAD_SN_MASK GENMASK(23, 20)/* bits [23:20] */ +#define PHY_CNFG_PAD_SN 0x0c/* NMOS TX drive strength */ +#define PHY_CNFG_PAD_SN_SG2042 0x08/* NMOS TX drive strength for SG2042 */ /* PHY command/response pad settings */ #define PHY_CMDPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x04)
@@ -148,10 +151,12 @@#define PHY_PAD_TXSLEW_CTRL_P 0x3/* Slew control for P-Type pad TX */ #define PHY_PAD_TXSLEW_CTRL_N_MASK GENMASK(12, 9)/* bits [12:9] */ #define PHY_PAD_TXSLEW_CTRL_N 0x3/* Slew control for N-Type pad TX */ +#define PHY_PAD_TXSLEW_CTRL_N_SG2042 0x2/* Slew control for N-Type pad TX for SG2042 */ /* PHY CLK delay line settings */ #define PHY_SDCLKDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x1d) -#define PHY_SDCLKDL_CNFG_UPDATE BIT(4)/* set before writing to SDCLKDL_DC */ +#define PHY_SDCLKDL_CNFG_EXTDLY_EN BIT(0) +#define PHY_SDCLKDL_CNFG_UPDATE BIT(4)/* set before writing to SDCLKDL_DC */ /* PHY CLK delay line delay code */ #define PHY_SDCLKDL_DC_R (DWC_MSHC_PTR_PHY_R + 0x1e)
@@ -159,10 +164,14 @@#define PHY_SDCLKDL_DC_DEFAULT 0x32/* default delay code */ #define PHY_SDCLKDL_DC_HS400 0x18/* delay code for HS400 mode */ +#define PHY_SMPLDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x20) +#define PHY_SMPLDL_CNFG_BYPASS_EN BIT(1) +/* PHY drift_cclk_rx delay line configuration setting */ #define PHY_ATDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x21)#define PHY_ATDL_CNFG_INPSEL_MASK GENMASK(3, 2)/* bits [3:2] */ #define PHY_ATDL_CNFG_INPSEL 0x3/* delay line input source */ +#define PHY_ATDL_CNFG_INPSEL_SG2042 0x2/* delay line input source for SG2042 */ /* PHY DLL control settings */ #define PHY_DLL_CTRL_R (DWC_MSHC_PTR_PHY_R + 0x24)
@@ -206,6 +215,11 @@ struct rk35xx_priv {u8 txclk_tapnum; }; +#define SG2042_MAX_CLKS 2 +struct sg2042_priv { +struct clk_bulk_data clks[SG2042_MAX_CLKS ]; +}; +struct dwcmshc_pltfm_data ;struct dwcmshc_priv {struct clk *bus_clk;
@@ -1017,6 +1031,125 @@ static int cv18xx_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)return ret; } +static inline void sg2042_sdhci_phy_init (struct sdhci_host *host) +{ +u32 val; + +/* Asset phy reset & set tx drive strength */ + val =sdhci_readl (host,PHY_CNFG_R ); + val &= ~PHY_CNFG_RSTN_DEASSERT ; + val |=FIELD_PREP (PHY_CNFG_PHY_PWRGOOD_MASK ,1 ); + val |=FIELD_PREP (PHY_CNFG_PAD_SP_MASK ,PHY_CNFG_PAD_SP_SG2042 ); + val |=FIELD_PREP (PHY_CNFG_PAD_SN_MASK ,PHY_CNFG_PAD_SN_SG2042 ); +sdhci_writel (host, val,PHY_CNFG_R ); + +/* Configure phy pads */ + val =PHY_PAD_RXSEL_3V3 ; + val |=FIELD_PREP (PHY_PAD_WEAKPULL_MASK ,PHY_PAD_WEAKPULL_PULLUP ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_P_MASK ,PHY_PAD_TXSLEW_CTRL_P ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_N_MASK ,PHY_PAD_TXSLEW_CTRL_N_SG2042 ); +sdhci_writew (host, val,PHY_CMDPAD_CNFG_R ); +sdhci_writew (host, val,PHY_DATAPAD_CNFG_R ); +sdhci_writew (host, val,PHY_RSTNPAD_CNFG_R ); + + val =PHY_PAD_RXSEL_3V3 ; + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_P_MASK ,PHY_PAD_TXSLEW_CTRL_P ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_N_MASK ,PHY_PAD_TXSLEW_CTRL_N_SG2042 ); +sdhci_writew (host, val,PHY_CLKPAD_CNFG_R ); + + val =PHY_PAD_RXSEL_3V3 ; + val |=FIELD_PREP (PHY_PAD_WEAKPULL_MASK ,PHY_PAD_WEAKPULL_PULLDOWN ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_P_MASK ,PHY_PAD_TXSLEW_CTRL_P ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_N_MASK ,PHY_PAD_TXSLEW_CTRL_N_SG2042 ); +sdhci_writew (host, val,PHY_STBPAD_CNFG_R ); + +/* Configure delay line */ +/* Enable fixed delay */ +sdhci_writeb (host,PHY_SDCLKDL_CNFG_EXTDLY_EN ,PHY_SDCLKDL_CNFG_R ); +/* +* Set delay line. +* Its recommended that bit UPDATE_DC[4] is 1 when SDCLKDL_DC is being written. +* Ensure UPDATE_DC[4] is '0' when not updating code. +*/ + val =sdhci_readb (host,PHY_SDCLKDL_CNFG_R ); + val |=PHY_SDCLKDL_CNFG_UPDATE ; +sdhci_writeb (host, val,PHY_SDCLKDL_CNFG_R ); +/* Add 10 * 70ps = 0.7ns for output delay */ +sdhci_writeb (host,10 ,PHY_SDCLKDL_DC_R ); + val =sdhci_readb (host,PHY_SDCLKDL_CNFG_R ); + val &= ~(PHY_SDCLKDL_CNFG_UPDATE ); +sdhci_writeb (host, val,PHY_SDCLKDL_CNFG_R ); + +/* Set SMPLDL_CNFG, Bypass */ +sdhci_writeb (host,PHY_SMPLDL_CNFG_BYPASS_EN ,PHY_SMPLDL_CNFG_R ); + +/* Set ATDL_CNFG, tuning clk not use for init */ + val =FIELD_PREP (PHY_ATDL_CNFG_INPSEL_MASK ,PHY_ATDL_CNFG_INPSEL_SG2042 ); +sdhci_writeb (host, val,PHY_ATDL_CNFG_R ); + +/* Deasset phy reset */ + val =sdhci_readl (host,PHY_CNFG_R ); + val |=PHY_CNFG_RSTN_DEASSERT ; +sdhci_writel (host, val,PHY_CNFG_R ); +} + +static void sg2042_sdhci_reset (struct sdhci_host *host,u8 mask) +{ +sdhci_reset (host, mask); + +if (mask &SDHCI_RESET_ALL ) +sg2042_sdhci_phy_init (host); +} + +static int sg2042_clks_enable (struct dwcmshc_priv *dwc_priv) +{ +int ret =0 ; +struct sg2042_priv *soc = dwc_priv->priv; + +if (soc) + ret =clk_bulk_prepare_enable (SG2042_MAX_CLKS , soc->clks); +return ret; +} + +static void sg2042_clks_disable (struct dwcmshc_priv *dwc_priv) +{ +struct sg2042_priv *soc = dwc_priv->priv; + +if (soc) +clk_bulk_disable_unprepare (SG2042_MAX_CLKS , + soc->clks); +} + +static int sg2042_init (struct device *dev,struct sdhci_host *host, +struct dwcmshc_priv *dwc_priv) +{ +int err; +struct sg2042_priv *soc =NULL ; + + soc =devm_kzalloc (dev,sizeof (struct sg2042_priv ),GFP_KERNEL ); +if (!soc) +return -ENOMEM ; + + soc->clks[0 ].id ="card" ; + soc->clks[1 ].id ="timer" ; + err =devm_clk_bulk_get_optional (mmc_dev (host->mmc),SG2042_MAX_CLKS , + soc->clks); +if (err) { +dev_err (mmc_dev (host->mmc),"failed to get clocks %d\n" , err); +return err; + } + + err =clk_bulk_prepare_enable (SG2042_MAX_CLKS , soc->clks); +if (err) { +dev_err (mmc_dev (host->mmc),"failed to enable clocks %d\n" , err); +return err; + } + + dwc_priv->priv = soc; + +return 0 ; +} +static const struct sdhci_ops sdhci_dwcmshc_ops = { .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width,
@@ -1066,6 +1199,16 @@ static const struct dwcmshc_pltfm_data sdhci_dwcmshc_pdata = { }, }; +static const struct sdhci_ops sdhci_dwcmshc_sg2042_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 = sg2042_sdhci_reset, + .adma_write_desc = dwcmshc_adma_write_desc, + .platform_execute_tuning = th1520_execute_tuning, +}; + #ifdef CONFIG_ACPI static const struct dwcmshc_pltfm_data sdhci_dwcmshc_bf3_pdata = { .pdata = {
@@ -1108,6 +1251,17 @@ static const struct dwcmshc_pltfm_data sdhci_dwcmshc_cv18xx_pdata = { }, }; +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_sg2042_pdata = { + .pdata = { + .ops = &sdhci_dwcmshc_sg2042_ops, + .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , + .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN , + }, + .init = sg2042_init, + .clks_enable = sg2042_clks_enable, + .clks_disable = sg2042_clks_disable, +}; +static const struct cqhci_host_ops dwcmshc_cqhci_ops = { .enable = dwcmshc_sdhci_cqe_enable, .disable = sdhci_cqe_disable,
@@ -1200,6 +1354,10 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { .compatible = "thead,th1520-dwcmshc", .data = &sdhci_dwcmshc_th1520_pdata, }, + { + .compatible = "sophgo,sg2042-dwcmshc", + .data = &sdhci_dwcmshc_sg2042_pdata, + }, {}, };MODULE_DEVICE_TABLE (of, sdhci_dwcmshc_dt_ids);
Signature · 1 line
2.25.1
PATCH v4 4/4 riscv: dts: add mmc controllers for Sophgo SG2042 SoC
In reply to Chen WangFrom: Chen Wang <[email protected]>
SG2042 has two MMC controller, one for emmc, another for sd-card.
--- .../boot/dts/sophgo/sg2042-milkv-pioneer.dts | 17 ++++++++++ arch/riscv/boot/dts/sophgo/sg2042.dtsi | 32 +++++++++++++++++++ 2 files changed, 49 insertions(+)
arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts +17 -0
@@ -14,6 +14,23 @@ chosen { }; }; +&emmc { + bus-width = <4>; + no-sdio; + no-sd; + non-removable; + wp-inverted; + status = "okay"; +}; + +&sd { + bus-width = <4>; + no-sdio; + no-mmc; + wp-inverted; + status = "okay"; +}; + &uart0 { status = "okay"; };
arch/riscv/boot/dts/sophgo/sg2042.dtsi +32 -0
@@ -346,5 +346,37 @@ uart0: serial@7040000000 { resets = <&rstgen RST_UART0>; status = "disabled"; }; + + emmc: mmc@704002a000 { + compatible = "sophgo,sg2042-dwcmshc"; + reg = <0x70 0x4002A000 0x0 0x1000>; + interrupt-parent = <&intc>; + interrupts = <134 IRQ_TYPE_LEVEL_HIGH>; + clocks = + <&clkgen GATE_CLK_AXI_EMMC>, + <&clkgen GATE_CLK_100K_EMMC>, + <&clkgen GATE_CLK_EMMC_100M>; + clock-names = + "core", + "timer", + "card"; + status = "disabled"; + }; + + sd: mmc@704002b000 { + compatible = "sophgo,sg2042-dwcmshc"; + reg = <0x70 0x4002B000 0x0 0x1000>; + interrupt-parent = <&intc>; + interrupts = <136 IRQ_TYPE_LEVEL_HIGH>; + clocks = + <&clkgen GATE_CLK_AXI_SD>, + <&clkgen GATE_CLK_100K_SD>, + <&clkgen GATE_CLK_SD_100M>; + clock-names = + "core", + "timer", + "card"; + status = "disabled"; + }; }; };
Signature · 1 line
2.25.1
Re: [PATCH v4 4/4] riscv: dts: add mmc controllers for Sophgo SG2042 SoC
Quoted 43 lines · Chen Wang
From: Chen Wang <[email protected]>
SG2042 has two MMC controller, one for emmc, another for sd-card.
Signed-off-by Chen Wang <[email protected]>--- .../boot/dts/sophgo/sg2042-milkv-pioneer.dts | 17 ++++++++++ arch/riscv/boot/dts/sophgo/sg2042.dtsi | 32 +++++++++++++++++++ 2 files changed, 49 insertions(+)arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts +17
-0@@ -14,6 +14,23 @@ chosen { }; }; +&emmc { + bus-width = <4>; + no-sdio; + no-sd; + non-removable; + wp-inverted; + status = "okay"; +}; + +&sd { + bus-width = <4>; + no-sdio; + no-mmc; + wp-inverted; + status = "okay"; +}; + &uart0 { status = "okay"; };arch/riscv/boot/dts/sophgo/sg2042.dtsi +0
-0
arch/riscv/boot/dts/sophgo/sg2042.dtsi uart0: serial@7040000000 { · line 352
Quoted 7 lines
arch/riscv/boot/dts/sophgo/sg2042.dtsi +4
-0@@ -346,5 +346,37 @@ uart0: serial@7040000000 { resets = <&rstgen RST_UART0>; status = "disabled"; }; + + emmc: mmc@704002a000 { + compatible = "sophgo,sg2042-dwcmshc"; + reg = <0x70 0x4002A000 0x0 0x1000>;
Lowercase hex.
arch/riscv/boot/dts/sophgo/sg2042.dtsi uart0: serial@7040000000 { · line 355
Quoted 3 lines
arch/riscv/boot/dts/sophgo/sg2042.dtsi +3
-0+ interrupt-parent = <&intc>; + interrupts = <134 IRQ_TYPE_LEVEL_HIGH>; + clocks =
Odd wrapping. Don't. See DTS coding style.
arch/riscv/boot/dts/sophgo/sg2042.dtsi uart0: serial@7040000000 { · line 359
Quoted 4 lines
arch/riscv/boot/dts/sophgo/sg2042.dtsi +4
-0+ <&clkgen GATE_CLK_AXI_EMMC>, + <&clkgen GATE_CLK_100K_EMMC>, + <&clkgen GATE_CLK_EMMC_100M>; + clock-names =
Ditto
arch/riscv/boot/dts/sophgo/sg2042.dtsi uart0: serial@7040000000 { · line 363
Quoted 4 lines
arch/riscv/boot/dts/sophgo/sg2042.dtsi +4
-0+ "core", + "timer", + "card"; + status = "disabled";
Best regards,
Krzysztof
Re: [PATCH v4 4/4] riscv: dts: add mmc controllers for Sophgo SG2042 SoC
In reply to Chen Wang$subject: riscv: dts: add mmc controllers for Sophgo SG2042 SoC
Could you add a sopho: prefix in that please?